TCP 三次握手和四次挥手
三次握手:
TCP是面向连接的服务,所以必须要先建立连接才能传输数据,最后在结束连接。
连接过程:
- 客户端先发送一个同步报文,即SYN项置1的报文,然后拟定一个序列号$x$,即$seq=x$,数据部分不携带任何字节发送给服务器。
- 服务器接收到同步报文后,要回复一个确认报文和同步报文(至于为什么会回复一个同步报文不清楚)。确认报文首先得ACK置1,然后确认号为$x+1$,即$ack= x+1$,(注意,小写的ack和大写的ACK不一样),因为确认报文的序列号代表的是希望收到发送方下一个字节的序号,因为之前发送方的报文并不携带数据信息,所以服务端希望得到的应该还是第$x$字节数据,但是TCP规定SYN报文不携带数据也要消耗掉一个序号,所以假定同步报文携带了一个数据字节。这同时还是一个同步报文,所以SYN项置1,并且设置序列号为$y$,将其发送给客户端。总结一下,就是ACK置1,SYN置1,$ack = x+ 1,seq = y$.
- 同理,客户端此时也要发送一个确认报文给服务器端,ACK置1,$ack = y+1$, 序列号是$seq = x+1$。(在这里客户端TCP协议一个数据字段都没有发送,但是序列号相比于第一步的$x$增加了1,因为同步报文默认占一个字节)
至于为什么要三次握手,而不是二次握手,就是在第二步服务器端发送完确认报文就结束?
是为了防止已经超时的客户端请求重新让服务器端开始一次TCP连接。详细过程为,假设客户端发送一个TCP同步请求,在网络中超时到达了服务端。然而在此过程种,客户端重新开起了一次TCP请求,并且和接收端完成了握手工作。当之前的TCP同步请求到达服务器端的时候,服务器端不清楚是之前发送的请求,于是当成了新的请求对待,也发送了一个确认报文给客户端。此时如果是二次握手,即没有客户端发送给确认报文给服务器端的情况下,这时客户端和服务器端共同开启了一个无用的连接,对于客户端没有影响,会在第二次握手时候将确认报文丢失,但是服务器端就被占用了一些资源。如果此过程是三次握手,那么服务器端只有在第三次接收到确认报文的时候才开辟资源,但是这个过程永远不会实现,因为第二次握手过程中,客户端已经将收到的确认同步报文丢弃掉了。
四次挥手
挥手过程:
- 客户端先发送一个FIN报文,结束报文。FIN首先先置1,其中的$seq = u$,u代表的是客户端下一个要发送的数据字节,但是这是一个结束报文,所以$u$,就是最后字节了。$FIN=1,seq=u$。此时客户端进入FIN-WAIT1状态。
- 服务器端发送一个确认报文。ACK首先置1,然后确认号为$ack=u+1$,同样应该设置为$u$,但是TCP规定,结束报文占用一个序号,所以相当于结束报文发送一个字节,这个字节序号为$u$,所以服务器端期望得到的是$u+1$序号的字节。序列号为当前已经发送的字节数的下一个,就是正常计算序列号,设为$v$,故$seq = v$。总结为$ACK=1,ack =u+1,FIN=1,seq=v$。此时服务器端进入CLOSE-WAIT状态。此时的网络状态是半关闭状态。也就是此时客户端是结束了向服务器端发送数据,但是服务器端还可以向客户端发送数据。
- 服务器发送一个结束报文和确认报文。所以FIN置1,序列号为当前已经发送的字节数的下一个,就是正常计算序列号,上一个发送的序列号为$v$,但是此时的序列号已经发生改变了,因为服务器端在半关闭状态时又发送了许多数据,此时设为$w$,即$seq=w$。确认报文设置,ACK置1,$ack = u+1$,因为客户端一直没有发送数据,所以服务器端希望接收到的仍是$u+1$号字节。$FIN=1,seq=w,ACK=1,ack=u+1$
- 客户端再回复确认报文。ACK置1,确认号为$w+1$,即$ack=w+1$,序列号为$u+1$,因为客户端一直没有发送数据,自从半关闭状态的时候。总结一下,$ACK=1,ack=w+1,seq=u+1$
具体内从都是参见谢希仁《计算机网络》