标签:占用 并发 端口 keep out 不可 为什么 环境 放弃
客户端收到服务端发送的 SYN 和 ACK 之后,发送ACK 的 ACK,之后处于 ESTABLISHED 状态,因为它一发一收成功了。服务端收到 对ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了。
为什么不是两次、四次或者更多次?
比如AB要建立连接,A发起一个连接但连接请求没有响应,可能包丢了、包绕弯路了、超时了等等,A于是继续给B发包,终于B收到了请求包但A并不知道,所以A可能还会继续发。B收到包之后,知道了A存在并且要和它建立连接。如果B不想建立连接,A重试一会后放弃,连接建立失败没有问题。如果B愿意建立连接,那就会发应答包给A。同样这个应答包会和请求包出现一样的问题,那么对于B不能认为连接建立好了。
B发送的应答包可能会发送多次,只要有一次到达A,那么A就认为连接已经建立了,因为A的消息有去有回,相当于两次握手。假如这时候连接已经建立,并且做了简单通信后,结束了连接。上面讲了A要建立连接的时候,可能会发送多个请求包。有的请求包绕了一大圈又回来了,B 会认为这也是一个正常的的请求,再次建立连接,但这个连接不会正常接发数据、也不会终结,B就一直等待。A发的消息有去有回,但B发出的消息没有回,所以两次握手肯定不行。其实三次握手中,A发给B回复的回复也会丢、绕路或者B挂了,按照这个逻辑B还要再发个确认就变成了四次握手,这样不停套娃多达几百次也可以,但这也不能保证就可靠了。TCP连接的设计原则是双发的消息都有去有回就基本可以了。
大部分情况下,A和B建立连接后会A会马上发送数据,如果A发给B的应答丢了,A后续发送的数据到达时,B可以认为连接已经建立;又或者B挂了,那么直接报错返回B不可达信息都没问题。如果A就是不发送数据,客户端可以开启keeplive机制,发送探活包。服务端设置规定时间,超时了就主动关闭,释放资源。
TCP把数据看成一个无结构、有序的字节流,一个报文段的序号是该报文段首字节的字节流编号。三次握手除了确保双方消息有去有回,最重要的是解决tcp包的序号问题。A、B双方互相告知对方包的起始序号。又会有个疑问,为什么一定要交换序号,不能从序号1开始发包吗?假设A给B发3个包,序号为1、2、3,但3包可能绕路了,没有正常到达B,A又重新发送。后来A掉线了,重新连上B后又从1开始,发送两个包1、2,但上次出问题的包3又回来了,发给了B,B认为这就是A要发给它的下一个包,于是出现错误。因此每个连接都要有不同的序号,序号的起始序号每4ms加一,等遇到重复的序号要4个多小时。比如3号包绕路了,就要隔4个多小时连接的起始序号才是3,这么长时间3号包已经无效了,因为IP包头里有TTL(生存时间)。
如果一切正常,进行第三次挥手A收到B的主动关闭请求并发送确认后进入TIME-WAIT状态,为什么需要这个状态呢?假设A发送完确认消息后直接关闭,如果B没收到这个确认消息,那B会重发结果就是B关闭失败。还有一种情况是A的端口空出来,但B还保持原来状态不知道A的情况。如果 A 的端口被一个新的应用占用了,这个新的应用会收到上个连接中 B 发过来的包,数据接收错误。所以A要进入TIME-WAIT状态,并且TCP设置了等待时间2MSL(报文段最大生存时间),任何报文在网络上存在超过这个时间将被丢弃。协议规定 MSL 为 2 分钟,实际应用中常用的是 30秒,1 分钟和 2 分钟等。还有一种情况是超过了2MSL,B依然没有收到对FIN的ACK。这时即便A收到了B重发的FIN,A会直接发送RST,表示重新开始挥手。
参考资料:《趣谈网络协议》刘超
《计算机网络:自顶向下方法》原书第六版 陈鸣译
标签:占用 并发 端口 keep out 不可 为什么 环境 放弃
原文地址:https://www.cnblogs.com/fly-bryant/p/13340927.html