把书读薄(TCP/IP详解 卷一 第十八章)
TCP的三次握手是过程是怎样的?
- 请求端(客户端)发起第一个SYN,执行主动打开,表示想要连接服务端,同时指明初始序号(ISN,比如这里的141553152)
- 服务端做出回应,指明自己的初始序号,执行被动打开,同时将确认序号设置成对客户端的初始序号加1,表示确认了客户端的SYN
- 客户端将确认序号设置成服务端的初始序号加1,表示确认了服务端的SYN
ISN:初始序号,可以看做是一个32比特的计数器,每4ms加1,详见RFC 793
TCP的四次挥手过程是怎样的?
- 请求端(客户端)想断开连接,于是发出一个FIN包
- 服务端接收到请求,在确认序号上对客户端的序号加1表示已确认
- 服务端关闭自己的连接,发出一个FIN包
- 客户端接收到请求,在确认序号上对服务端序号加1表示已经确认
TCP连接是全双工的,每个方向都必须单独关闭
建立连接时如果超时了会发生什么事情?
出现场景
服务器在客户端建立连接时刚好断电。可以看出客户端进行了重试,但是重试之间的时间间隔第一次是5.81秒,而第二次间隔是24.00秒。
这种超时重试时间间隔对于BSD版的TCP软件实现来讲,是由于500ms的定时器存在。第一次的间隔一般在5.5-6秒任意时刻超时,而第二次一般稳定在24秒。这是由于TCP在500ms以内获得系统控制的瞬间,可能系统会优先处理其它中断,从而第一次计数器减1会发生在0-500ms的任意一个时刻。而每次TCP 500ms定时器被内核调用时都会修正,因而后续稳定
tos 0x10 表示IP数据报内的服务类型,这里的值为DNS的udp查询
异常终止连接会发生什么事情?
连接一方发送复位报文来中途释放连接【正常是发送FIN】
异常释放的一端将返回RST报文段,收到的一方将终止连接,并通知应用层进行复位,接收方并不对RST报文进行确认。
什么是TCP的半关闭?
TCP的一端结束发送后,仍然能接收另一端发送的数据。
应用场景
想仅进行一次排序的操作。流程为从客户端读取用户输入的文件,从服务端进行排序,然后客户端接收排序的结果。对于客户端来讲,当文件传输完毕之后不会再发送数据,此时可以直接关闭,而服务端需要先对数据拍完序,再做回应,此时客户端要保持接收数据的能力,这样就适合使用半关闭(服务端通知客户端也可以使用另外1次TCP连接,但是半关闭可以省掉多余1次的连接过程)
什么是TCP的半打开?
连接的一端已经关闭或异常终止,但是另一端确不知道这个情况。
出现场景
客户端和服务端正在正常通信的时候,突然服务器断电了,这个时候客户端并不知道服务器断电,对于这种情况,如果服务器立即恢复电源再立马重启,当客户端在服务器重启之后发送数据时,服务端则回复复位标识,即TCP的标识位R设置为1,客户端收到信息,知晓连接终止
类似场景:客户使用完自己的电脑,直接把电脑电源线拔了,这时服务器并不知道客户端已经消失,后续客户端再开机又会建立新的连接,这样导致服务器会存在许多半打开的连接
如果TCP两端同时打开会怎么样?
通信双方发送的SYN同时到达对方,且一端发送的端口和另一端要求接收的端口一样。
出现场景
主机A应用程序使用本地端口7777,与主机B端口8888执行主动打开,主机B应用程序则使用本地端口8888,与主机A端口7777执行主动打开
报文状态变迁如下
整个过程打开需要4次报文段交换,tcp本身的设计保证,这种场景仅建立了1个连接
其它协议族可能建立两条,比如OSI运输层
如果TCP两端同时关闭会怎么样?
通信双方都执行主动关闭。状态变化如下:
交换的报文段和正常的关闭使用的数目一样。
TCP的状体变迁过程是怎样的?
3次握手的状态变迁
连接建立超时状态变迁
同时打开状态变迁
4次挥手状态变迁
同时关闭状态变迁
收到RST的可能状态变迁
RST发生一般是接收端收到的包很明显和当前连接没有啥关系,这时候就触发RST包产生
-
由于某种未知因素,客户端发出的SYN多次,但是服务端接收到的却是旧的SYN,这时候客户端发出RST,服务端收到RST重新建连接
-
处于半打开状态,连接已经建立的时候,突然客户端挂了,这时当客户端尝试再次打开连接或者服务端再次发送数据都会让服务端收到RST
上图为客户端CRASH然后客户端重连,下图为客户端CRASH然后服务端向客户端返回数据
从SYN_RECEVIED状态进入FIN_WAIT_1状态
此时没有需要发送的东西,队列中也没有未完成的东西需要发送,就生成一个FIN包,发送出去,断开连接
有要发送的东西,比如ack,就去建立连接
2MSL等待时间是什么?
MSL(Maximum Segment Lifetime)是报文段的最大生存时间。
生存时间是有限的,由于TCP报文段是以IP数据报在网络内传输,而IP数据报通过TTL的跳数限制,因而报文段被丢弃之前,在网络内生存时间有限
当TCP执行主动关闭并发回最后一个ACK,该连接必须在TIME_WAIT状态内等待2倍的MSL时间。
原因:1:TCP主动关闭端发送的ACK如果丢失了,被动关闭端再次重发FIN,这时候的时间等待能够使得TCP主动关闭端发送最后的ACK不会丢失;2下次新的连接可能会复用同一个端口,如果由于网络延迟,老的数据才到,会与新数据发生混合,等待2MSL可以使得老数据完全消失
在2MSL时间段之内,定义这个连接的插口(客户端IP和端口,服务端IP和端口),不能再被 被动断开方使用
如果服务端的连接突然断开再立马重新启动,服务器的这个端口在2MSL时间内客户端无法连接【这里客户端是被动断开方】;同理如果是客户端自己断开,再立马使用相同的端口,在2MSL时间内去连服务器也是无法成功的【这里服务器是被动断开方】。这种场景客户端可以再随便换一个端口即可,但是服务端的一般应用端口都是固定的,容易造成麻烦
如果多个请求同时到达服务端,服务端是如何处理的?
TCP服务器会专门安排一个进程,它永远处于LISTEN状态,用来接收客户端的请求,当请求被接收时,系统中的TCP模块就会创建一个处于ESTABLISHED状态的进程处于LISTEN状态的进程不能接收数据报文段,处于ESTABLISHED状态进程不能接收SYN报文段
伯克利TCP实现多连接处理规则为:
- 正等待连接请求一端有一个固定长度的连接队列,队列中的连接已被TCP接受,但是应用层还没有感知
- 应用层指明改队列的最大长度,它通常称为积压值(backlog),取值范围是0-5
- 新连接到达时,如果连接队列有空间,TCP模块将对SYN进行确认并完成连接建立。但应用层只有在3次握手的第3次报文段接收到后才知道这个新连接
- 新连接到达,但是连接队列没有空间,TCP模块不理会SYN,也不发回RST,如果应用层没有及时接受已被该TCP接受的连接,连接占满,客户端的主动打开最终将超时
TCP接收连接是放入连接队列,应用层接收连接是从队列中移除
队列的积压数与服务器能处理的最大连接数没有关系