今天详细学习下TCP链接的三次握手四次挥手,因为开发web服务还是会经常遇到一些网络问题的。其实这方面的资料很多,可能我们看过很多次但也忘了无数次[捂脸],这次我主要通过抓包例子来展示这个过程。
- TCP传输控制协议(TransmissionControlProtocol)
他的特点是基于流、提供可靠数据传输,先建立连接再传输数据。提供如超时重传、流控等各种机制,这样的特点同时也导致了tcp会使用更多的连接,占用更多的资源。UDP则是直接发送数据,不保证数据的到达与接收。我们再把这个流程图拿过来瞅瞅。
- 三次握手
这里我用本机50319端口请求远端80服务, 能清楚的看到三次TCP的连接,你是否有疑问为什么是三次,不是两次,不是四次,其实这里是兼容安全与效率。
我们说TCP数据保证基于SYN与ACK的存在,其实这里明显看到请求号72(也就是80->50319的回复)是将SYN+ACK合为了一条数据返回,这里我想应该可以拆开吧,但是拆开浪费一次链接。所以这里建立连接需要三次。
再来说下三次握手:
小明:你好丽丽,在吗?我是小明 请求号65 50319---->SYN(Seq=0)------>80
小丽:你好小明,我在呀~~ 80->SYN+ACK(Seq=0,Ack=1)-->50319
小明:好的,那我们开始谈谈心吧!! 50319->ACK(Seq=1, Ack=1)---->80
小丽:[爱慕] Established
小明:[送心] Established
- 四次挥手
这里先说明一点,HTTP1.1之后能自带keep-alive属性,也就是说同一个客户端的http请求可以共用一个tcp连接,这样能防止tcp连接的浪费,截图说明
我们在测试的时候可以关闭这个keep-alive, 在请求的时候设置connetion:close就可以了,这样可以方便我们抓包验证。如果开着的话,当前的tcp连接就不会立刻断开的截图说明
再说回四次挥手,我们看到请求号(212)80->56427发送FIN标识的消息,这代表80端要结束连接了,56427->80回复了ACK,请求号(214), 随后呢56247->80发送FIN标识请求号(215),代表自己也没有消息发送可以结束了,随后请求号(216)80->56247发送ACK确认,至此连接关闭。
.......
小明:好吧,我说完了! 80-----FIN----->56427
小丽:嗯嗯! 56427------ACK--->80
小丽:我也没话说了! 56427-----FIN----->80
小明:再见!!! 80-----ACK----->56427
小明:[流泪]closed!!
小丽:[吐]closed!!
那为啥是四次挥手呢,如果是三次就像连接建立一样将最后56427->80的ACK+FIN合并为一条可以吗,当然不可以,这是因为TCP的连接双方能发消息也能接受消息,FIN的发出代表本方将关闭消息发送,而无法确认对方是否还有消息发送过来,估需要双方分别确定已关闭消息发送。
- 关于状态的说明
这里我们在服务端加入sleep操作限制连接的立刻断开如代码
<?phpsleep (60);echo "hello World ";
我们观察下链接状态的变化
服务端状态流转:
LISTEN->SYN-RECEIVED->ESTABLISHED->CLOSE-WAIT->LAST-ACK->CLOSED
客户端状态流转:
SYN-SENT->ESTABLISHED->FIN-WAIT1->FIN-WAIT2->TIME-WAIT->CLOSED
这里可能跟上面说的有差别,是因为我们这里是80主动关闭的连接。另外有些状态流转太快,我根本看不到啊[吐血]
状态我还需要再学习学习,里面的玩意太多了,下个分享,我们找一些例子来学习下,重点是TIME_WAIT、2SML啥的。
总结:
- TCP的消息可靠性通过SYN+ACK实现
- TCP三次握手+四次挥手是有原因的
- TCP的连接双方都有各自的状态流转
- 要通过一些工具如netstat、tcpdump去实际查看网络连接状况