参考书籍:TCP-IP详解
基本概念
ISN: 初始的序列号,Sequeue Number,TCP 协议栈为每一个封包都会分配一个sequence number,主要用来保证顺序的问题
MSS:最大报文长度,发送的报文不要超过这个值,一般情况下MTU-IP Header - TCP Header
ACK:确认序号,表明下一个需要接收的包的Sequeue number,可以通过这个来尽最大可能保证不丢包
Window Size: 滑动窗口,解决流量控制
三次握手(Three handshake)
1.请求端先发送一个SYN包(图中的103包),告诉连接服务器端口及ISN,如下图Seq = 0,MSS = 1460(MTU = 1500) Window Size = 65535
2.服务器会对SYN包做一个回应,ACK = 1(103包的Seq + 1), 即期望获得Seq = 1的包,然后告知Windwos和MSS
3.客户端收到[SYN ACK]包,然后将Seq = 1发送一个ACK包,对服务器来的ACK进行确认
这样就完成了三次握手,成功建立了一个连接,接下来就可以正常发送数据了!
说明:在TCPdump中看到的三次握手的seq number总是为0,但是实际上真实的协议栈不是这样的,ISN是一个随时间变化的值,不能是Hard Code,在这里如此实际上是Tcpdump做了优化,显示了一个相对的值,可以通过右键,Protocal option中的Ralative SeqNum取消掉即可。
下图是三次握手的示意图,X,Y就是一开始的ISN了
对于Seq number是如何变化的,可以看下整个流的流量图,这里可以看到一点:单独的ACK不会消耗Seq number,Seq Number的增加是和传输的字节数相关的,可以看到三次握手之后,客户端开始发数据,这个时候Seq = 1, 发了161长度的数据包,对方回复了一个ACK = 162,也就说162前面的我已经都收到,请发162及之后的数据,接着 服务器又回复了一个1340长度的数据包,客户端给予一个ACK = 1341的确认!
四次挥手
终止一个连接要经过4次挥手,其实这个主要是由于TCP的半关闭造成的,TCP属于全双工的通讯,既能发又能收,当然可以关闭一部分,比如说让这个接口只能收不能发,这就是半关闭了,每一方都需要关闭,才能完成真正的关闭!
1)一般情况下客户端首先关闭,即发起一个FIN包,首先执行关闭的一端叫主动关闭,另一方成为被动关闭
2)服务器收到客户端的FIN包之后,会发会一个ACK包,确认序号为收到的需要加一,说明FIN包和SYN包一样都占用一个序号
3)客户端收到ACK包之后,说明客户端已经半关闭了,这个时候只能接收数据包,但是不能发送数据包
4)如果服务器也完成了发送数据需要关闭链接,TCP端就会发送一个FIN包给客户端
5) 客户端收到FIN包之后,就回复一个ACK表示收到,连接关闭
详细的过程可以参考下图:
连接建立超时
很多状况下,客户端无法连接到服务器上,基本都是发送SYN包,服务器端由于一些故障,没有回复SYN ACK,可以看一个实验的tcpdump结果,重新发送SYN包的事件间隔分别是 1s 2s 4s 8s 16s 32s,这个规律很好寻找,时间按照2^n次方的规律递增!
TCP的半关闭
TCP提供了连接的一端在结束它的发送后还能接收来自另外一端数据的能力。这就是所谓的半关闭,不过这种Case在应用程序中比较少的使用。
如果应用程序不调用close而调用shutdown,且第二个参数值为1,则这个socket的API支持半关闭!其实对于全双工的TCP协议来讲,只是关闭了发送数据的功能,但是还可以接收数据!
下图显示了一个典型的列子,让左边的客户端开始半关闭,发送FIN包,然后右端收到FIN包之后认为对端已经发送完数据了,回复ACK,这条路就彻底被切断了,目前的状况客户端只能收不能发了,所以右端的服务器仍然可以write数据给客户端,到服务器真正把所有数据发完的时候,会发FIN包来关闭连接,客户端收到FIN,回复ACK,连接彻底关闭。 不过再次重申 这种场景比较少用哦,了解即可。
https://blog.csdn.net/wdscq1234/category_6240857.html