三次握手
和女朋友异地恋一年多,为了保持感情我提议每天晚上视频聊天一次。
从好上开始,到现在,一年多也算坚持下来了。
问题
有时候聊天的过程中,我的网络或者她的网络可能会不好,视频就会卡住,听不到对方的声音,过一会儿之后才会恢复。
中间双方可能就要不断的确认网络是否恢复,但是有时候会:
她:“你可以听到了吗?”
我:“可以了,你呢?”
她:“喂喂,你可以听到了吗?”
我:“可以了,我可以听到了,你呢?”
她:“你可以听到了吗?”
…
这种情况很蛋疼,那么怎样才能找一个简单的办法,让两个人都确认自己可以听到对方的声音,对方也可以听到自己的声音呢?
注:以下情节纯属虚构
CP建立连接为什么是三次握手,而不是两次或四次?
TCP,名为传输控制协议,是一种可靠的传输层协议,IP协议号为6。
顺便说一句,原则上任何数据传输都无法确保绝对可靠,三次握手只是确保可靠的基本需要。
于是有了如下对话:
我:1+1等于几(SYN,seq=x)?
她:2,2+2等于几(SYN=1,ACK=x+1,seq=y)?
我:4(ACK=y+1,seq=z)
首先两个人约定协议
1.感觉网络情况不对的时候,任何一方都可以发起询问
2.任何情况下,若发起询问后5秒还没收到回复,则认为网络不通
3.网络不通的情况下等1min路由器之后再发起询问
对于我而言,发起 “1+1等于几”的询问后
-
若5s内没有收到回复,则认为网络不通
-
若收到回复,则我确认①我能听到她的消息 ②她能听到我的消息,然后回复她的问题的答案
对于她而言,当感觉网络情况不对的时候
-
若没有收到我的询问,则她发起询问
-
若收到“1+1等于几”,则她确认 ①她可以听到我的消息,然后回复我的问题的答案和她的问题“2,2+2等于几”
-
若5s内没有收到我的回复“4”,则她确认 ②我听不见她的消息
-
若5s内收到了我的回复“4”,则她确认 ②我可以听见她的消息
这样,如果上面的对话得以完成,就证明双方都可以确认自己可以听到对方的声音,对方也可以听到自己的声音!
四次挥手断开连接阐述:
第一次挥手:双方交流的差不多了,此时客户端也已经结尾了,接下来要断开通信连接,所以告诉服务端“我说完了(FIN)”,此时自身形成等待结束连接的状态。
第二次挥手:服务端知道客户端已经没话说了,服务端此时还有两句心里话要给客户端说,“我知道你说完了(ACK),我再给你说两句,&*……%¥”。
第三次挥手:此时客户端洗耳恭听继续处于等待结束的状态,服务器端也说完了,自身此时处于等待关闭连接的状态,并对告诉客户端,“我说完了,咱们断了吧(FIN)”。
第四次挥手:客户端收知道服务端也说完了,也要告诉服务端一声(ACK),因为连接和断开要双方都按下关闭操作才能断开,客户端同时又为自己定义一个定时器,因为不知道刚才说的这句话能不能准确到达服务端(网络不稳定或者其他因素引起的网络原因),默认时间定为两个通信的最大时间之和,超出这个时间就默认服务器端已经接收到了自己的确认信息,此时客户端就关闭自身连接,服务器端一旦接收到客户端发来的确定通知就立刻关闭服务器端的连接。
到此为止双方整个通信过程就此终结。这里要声明一下:断开链接不一定就是客户端,谁都可以先发起断开指令,另外客户端和服务端是没有固定标准的,谁先发起请求谁就是客户端。
为什么要设置时间为 2MSL?
MSL 是Maximum Segment Lifetime,译为“报文最大生存时间”,任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
等待 2MSL 时间主要目的是怕最后一个 ACK 对方没收到,那么对方在超时后将重发第三次握手的 FIN ,主动关闭端接到重发的 FIN 包后,系统收到该分组后,可以再发一个 ACK 应答包。还有就是等来该连接在网络上的所有报文都传输完毕,所以处于 TIME_WAIT 状态时候,两端的端口都是不可用的,迟到的报文都会被废弃。
如果我们设置的时间少于 2MSL ,旧的连接刚刚关闭,这个时候有同样五元组的新连接进来了,而之前的连接还有残留报文在网络上,就会干扰新的连接的使用。
反之,如果连接处于 TIME_WAIT 过长,造成新 socket 无法复用这个端口,即使这个连接完全废弃(通常来说一个端口释放后会等待两分钟之后才能再被使用)。就像拉完屎还占着茅坑,可以尝试使用下SO_REUSEADDR(socket 参数),比如在服务停止后立即重启,这个时候可能会遇到原先的连接还处于 TIME_WAIT 状态,导致无法绑定原先的端口,就可以使用 SO_REUSEADDR。
tcp_timestamps: Boolean,默认1,表示tcp通讯的时候是否是否使用时间戳。如下图,在 TCP 头部信息的扩展头部字段中就附带了时间戳,数据长度为两个4字节。TSval是该数据报发送出来的时间,TSecr是回显时间戳(即该ack对应的data或者该data对应的上次 ack 中的 TSval 值)