前言
看过前面有关两篇HTTP的文章的同学,想必对HTTP已经有了一定的了解。在HTTP初始(一)中提到过TCP/IP四层网络模型,这次我们就来详细了解一下TCP传输。因为时间和篇幅所限,本篇讲分为两章,本章讲TCP的三次握手,下章讲TCP的四次挥手,以及一些常见问题。
TCP的状态转化
先知全貌再看细节是很不错的学习方法,以后我的写作风格也尽量向这方面靠拢。所以在具体讲解TCP的三次握手和四次挥手前,我们先来整体看下TCP是如何运作的。
(该图片来源自网络)我们先来具体了解下各个状态的具体含义和关系,前5步是TCP三次握手,后六步是TCP四次挥手:
CLOSED:起始点,在超时或者连接关闭时进入此状态;Client和Server的初始态都应是CLOSED。
LISTEN:Server端在等待连接时的状态,Server端为此要调用Socket、bind、listen函数,就能进入此状态。这称为应用程序被动打开(等待客户端来连接)。
SYN-SENT:客户端发起连接,发送SYN给服务器端。如果服务器端不能连接则进入CLOSED状态。
SYN-RCVD:与3对应,服务器端接受客户端的SYN请求,服务器端由LISTEN状态进入SYN-RCVD状态。同时服务器端要回应一个ACK,发送一个SYN给客户端;另一种情况是,客户端在发起SYN的同时接收到服务器端的SYN请求,客户端会由SYN-SEBT转换到SYN-RCVD状态。
ESTABLISHED:服务器端和客户端在完成3次握手后进入状态,说明已经可以开始传输数据了。
FIN-WAIT-1:主动关闭的一方,由状态5进入此状态。具体动作是发送FIN给对方。
FIN-WAIT-2:主动关闭的一方,接收到对方的FIN ACK,进入此状态。由此不能再接收对方的数据,但是能够向对方发送数据。
CLOSE-WAIT:接收到FIN以后,被动关闭的一方进入此状态。具体动作是再接收到FIN的同时发送ACK。
LAST-ACK:被动关闭的一方,发起关闭请求,由状态8进入此状态。具体动作是发送FIN给对方,同时再接收到AKC时进入CLOSED状态。
CLOSING:两边同时发起关闭请求时,会由FIN-WAIT-1进入此状态。具体动作是接收到FIN请求,同时响应一个ACK。
TIME-WAIT:这个状态比较复杂,也是我们最常见的一个连接状态,有3个状态可以转化为此状态。
- 由FIN-WAIT-2转换到TIME-WAIT,具体情况是:在双方不同时发起FIN的情况下,主动关闭的一方在完成自身发起的关闭请求后,接收到被动关闭一方的FIN后进入的状态。
- 由CLOSING转换到TIME-WAIT,具体情况是:在双方同时发起关闭,都做了发起FIN的请求,同时接收到了FIN并做了ACK的情况下,这时就由CLOSING状态进入TIME-WAIT状态。
- 由FIN-WAIT-1转换到TIME-WAIT,具体情况是:同时接收到FIN(对方发起)和ACK(本身发起的FIN回应),它与CLOSING转换到TIME-WAIT的区别在于本身发起的FIN回应的ACK先于对方的FIN请求到达,而由CLOSING转换到TIME-WAIT则是FIN先到达。
TCP报文
“TCP报文是TCP传输的数据单元,也叫做报文段、数据包。
”
- 端口号:用来标识同一台计算机的不同的应用进程。
- 源端口(16位):与源主机IP地址一起标识源主机的一个应用进程。
- 目的端口(16位):和源主机IP地址一起标识目的主机的一个应用进程。IP报文中的源主机IP地址、目的主机的IP地址和源端口、目的端口确定了唯一一条TCP连接。
- 序列号seq(32位):标识从TCP源端向TCP目的端发送的数据字节流,表示这个报文段中的第1个字节的数据编号。在TCP传送的流中,每一个字节一个序号。比如:一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。
- 确认号ack(32位):存储发送确认的一端所期望收到的下一个序列号seq。确认号ack是上次已成功收到的数据字节的序列号seq+1。只有ACK标志为1时确认号字段才有效。TCP为应用层提供全双工服务,这就意味着数据能在两个方向上单独进行传输。因此,连接的两端都必须保持每个方向上的传输数据的序列号。
- 同步序号SYN:在连接建立时同步序列号。SYN=1、ACK=0表示:这是一个连接请求报文段。若同意连接,则在响应报文段中,SYN=1,ACK=1。而且,SYN这个标志位只在”三次握手阶段“,也就是TCP建立连接阶段才会为1,完成后被置0.
- 确认号标志ACK:当ACK=1时,确认号字段才有效。
- 终止标志FIN:用于释放连接,FIN=1表示:数据发送方的数据已发送完毕,并关闭本方数据流。
TCP三次握手
“其实三次握手就是用来建立TCP连接的,TCP数据在传输之前需要进行3次通信,一般被称为“三次握手”。这种建立连接的方式可以防止产生错误的连接,TCP使用的流量控制协议时可变大小的滑动窗口协议。
”
- 第一次握手:客户端发送SYN(seq=x)报文到服务器端,并进入SYN_SENT状态。
- 第二次握手:服务器端收到来自客户端的SYN报文,向客户端回应一个SYN(seq=y)和ACK(ack=x+1)报文,并进入SYN_RCVD状态。
- 第三次握手:客户端收到来自服务器端的SYN+ACK报文,向服务器端回应一个确认报文ACK(ack=y+1),发送完毕后,客户端和服务器端都进入ESTABLISHED状态。
在三次握手完成后,TCP客户端和服务器端成功建立连接,就可以传输数据了。
如此教科书般的回答,我也不是很满意,下面我们来从西瓜籽和大西瓜的对话中的了解下,什么是TCP三次握手:第一次:
西瓜籽:我是西瓜籽,大西瓜你真帅!
说明:西瓜籽会夸人。第二次:
大西瓜:我收到了你的夸赞,我是大西瓜,其实西瓜籽你也挺不错的!
说明:大西瓜可以接受别人的夸赞,也会夸人。第三次:
西瓜籽:我也收到了你的夸赞,我现在越看你越帅!
说明:西瓜籽也能接受别人的夸赞。
这俩人简直志同道合,然后就开始了双方的互夸Time.......(数据传输)
总结,我认为TCP三次握手有两个目的:一:是为了确保连接的两端都做好了发送和接收数据的准备工作二:每方都具有双方传输数据的序列号