TCP
协议
按层次分,TCP
位于传输层,TCP
协议全称是(Transmission Control Protocol
)传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议
TCP
协议特点
面向连接
使用 TCP
通信的双方必须先建立起连接,然后才能开始数据的读写。建立连接后双方的系统内核会为该连接分配必要的系统资源,用来管理连接的状态和传输在连接上的数据
可靠的
TCP
采用发送应答机制,即发送端发送的每个TCP
报文段都必须得到接收方的应答后才认为TCP
报文段传输成功。序号也保证了传送到接收端实体的包的按序接收TCP
还具有超时重传机制,发送端在发出一个TCP
报文段之后启动定时器,若在超时时间范围后还没收到接收端的应答信号,它将重发该数据报文。而UDP
协议与IP
协议一致,提供的是不可靠服务,数据确认和超时重传都需要在上层应用实现TCP
报文段最终是以IP
数据报发送的,IP
数据报到达接收端可能是重复/乱序的。所以TCP
发送模块还会为每个包指定一个序号,TCP
接收模块对接收到的TCP
报文段重排、整理,再交付应用程序
TCP
还提供流量控制和拥塞控制,防止过多的数据注入到网路中,缓解压力
单播和全双工
单播:每条 TCP
传输连接只能有两个端点,只能进行点对点(一对一)的单播数据传输,以基于广播和多播(目标是多个主机地址)的应用程序不能使用 TCP
服务
全双工:TCP
还是一个双向对称的全双工协议,一个 TCP
连接存在双向的读写通道,可以使数据在两个方向上同时进行传送操作,在发送数据的同时也能够接收数据,两者同步进行,就像平时打电话一样,说话的同时也能够听到对方的声音
半双工:是指一个虽然数据可以在一个信号载体的两个方向上传输,但是不能同时传输,时间段内只有一个动作发生
单工:是说数据传输是单向的,通信双方中,一方固定为发送端,一方则固定为接收端。信息只能沿一个方向传输
TCP
的三次握手
当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠,这样才能保证正确收发数据。为了准确无误地将数据送达目标处,TCP
协议采用了三次握手策略。用 TCP
协议把数据包送出去后,TCP
不会对传送后的情况置之不理,它一定会向对方确认是否成功送达

所谓三次握手,即建立 TCP
连接,就是指建立一个 TCP
连接时,需要客户端和服务端总共发送 3
个包以确认连接的建立。在 socket
编程中,这一过程由客户端执行 connect
来触发
- 最开始客户端和服务器都是出于
closed
状态 - 第一次握手:建立连接时,客户端发送
syn
包(syn=x
)到服务器,并进入SYN_SENT
状态,等待服务器确认。SYN
:同步序列编号 - 第二次握手:服务器收到
syn
包,必须确认客户的SYN
(ack=x+1
),同时自己也发送一个SYN
包(syn=y
),即SYN+ACK
包,此时服务器进入SYN_RECV
状态 - 第三次握手:客户端收到服务器的
SYN+ACK
包,向服务器发送确认包ACK
(ack=y+1
),此包发送完毕,客户端和服务器进入ESTABLISHED
(TCP
连接成功)状态,完成三次握手 - 若在握手过程中某个阶段莫名中断,
TCP
协议会再次以相同的顺序发送相同的数据包
简单的说,握手过程中主要使用了 TCP
的标志:SYN
(synchronize
) 和 ACK
(Acknowledgement
)。发送端首先发送一个带 SYN
标志的数据包给对方。接收端收到后,回传一个带有 SYN
和 ACK
标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK
标志的数据包,代表“三次握手”结束,TCP
连接成功。若在握手过程中某个阶段莫名中断,TCP
协议会再次以相同的顺序发送相同的数据包
TCP
的四次挥手
四次挥手即终止 TCP
连接,就是指断开一个 TCP
连接,当一方完成它的数据发送任务后就能通过发送一个 FIN
来终止这个方向的连接,但是由于全双工机制,收到一个 FIN
只意味着这一方向上没有数据流动,一个 TCP
连接在收到一个 FIN
后仍能发送数据。TCP
全双工的每个方向都必须单独进行关闭,因此需要客户端和服务端总共发送 4
个包以确认连接的断开
- 第一次挥手:客户端首先发送一个
FIN =1 ,seq = u
(等于前面客户端已经传送的数据的最后一个字节的序号加1
(TCP
规定,FIN
报文段即使不携带数据,也要消耗一个seq
序号),用来表示关闭客户端到服务器的数据传送,客户端进入FIN_WAIT_1
状态 - 第二次挥手:服务器收到
FIN
后,发送一个ACK = 1
给客户端,ack = u+1,seq = V
(等于前面服务器已经传送的数据的最后一个字节的序号加1
),此后服务器进入CLOSE_WAIT
状态。客户端收到之后则进入FIN-WAIT-2
状态,等待服务器进一步发送连接释放报文(在这之间还是需要接并处理受服务器发送的最后的数据) - 第三次挥手:服务器发送一个
FIN = 1,seq = w
(在第二次和第三次挥手过程中服务器可能又发送了一些数据,因此假定为N
),ack = u+1
(TCP
规定,ACK
报文段可以携带数据,但是如果不携带数据则不消耗序号),ACK = 1
,用来关闭服务器到客户端的数据传送,服务器进入LAST_ACK
状态,等待客户端最后确认 - 第四次挥手:客户端收到
FIN
后,接着发送一个ACK = 1
给服务器,ack = w+1,seq = u+1
,客户端进入TIME_WAIT
状态,服务器在收到确认之后进入CLOSED
状态,完成四次挥手 - 客户端的
TIME_WAIT
状态会持续2*MSL
(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃)时间,若该时间段内没有服务器的重发请求的话,客户端就进入CLOSED
状态
TCP
总结
为什么建立连接是三次握手,而关闭连接却是四次挥手
因为当 Server
端收到 Client
端的 SYN
连接请求报文后,可以直接发送 SYN+ACK
报文。其中 ACK
报文是用来应答的,SYN
报文是用来同步的。但是关闭连接时,当 Server
端收到 FIN
报文时,很可能并不会立即关闭 SOCKET
,所以只能先回复一个 ACK
报文,告诉 Client
端,“你发的 FIN
报文我收到了”。只有等到我 Server
端所有的报文都发送完了,我才能发送 FIN
报文,因此不能一起发送。故需要四步握手
为什么客户端最后要等待 2*MSL
时间
- 保证客户端发送的最后一个
ACK
报文能够到达服务器,因为这个ACK
报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK
报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2*MSL
时间段内收到这个重传的报文,接着给出回应报文,并且会重启2*MSL
计时器 - 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个
2*MSL
时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文
为什么不能用两次握手进行连接
3
次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机 S
和 C
之间的通信,假定 C
给 S
发送一个连接请求分组,S
收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S
认为连接已经成功地建立了,可以开始发送数据分组。可是,C
在 S
的应答分组在传输中被丢失的情况下,将不知道 S
是否已准备好,不知道 S
建立什么样的序列号,C
甚至怀疑 S
是否收到自己的连接请求分组。在这种情况下,C
认为连接还未建立成功,将忽略 S
发来的任何数据分组,只等待连接确认应答分组。而 S
在发出的分组超时后,重复发送同样的分组。这样就形成了死锁
如果已经建立了连接,但是客户端突然出现故障了怎么办
TCP
还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2
小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75
秒钟发送一次。若一连发送 10
个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接