1,只要client收到server的syn+ack,发送ack,client就认为三次握手建立完成,状态变为Established。阻塞的connect调用成功返回;对于非阻塞的connect调用,都会立马返回,使用select、poll或者epoll机制来判断socket是否可写来判定连接是否建立。
Established状态下的client自然是可以发送数据给server的。2,如果client的最后一个ack,中途丢失或者被server主动忽略或丢弃,server在定时器溢出后,会重发syn+ack,client向server发送数据,server并不会返回Rst。
要模拟这种场景,有两种方式:1)收到server的syn+ack后,拔掉客户端的网线;2)让server端的accept队列塞满,主动丢弃ack。第一种场景模拟起来,难度比较大,于是我们采用第二种。
我采用go写的server来模拟。将net.core.somaxconn设置为2(因为go中listen调用,传入的即为系统的上限制),方便模拟。客户端发送10个connect请求。
测试结果中,反映了下面几点:
1)客户端在发送完ack后(13:48:52.999239),立马(13:48:52.999879)开始发送数据;
2)发送的数据超时后,开始重试;
3)收到服务器重发的syn+ack后,客户端发送ack;
4)当服务器的syn+ack重试次数超过系统设置值后,断开连接,发送Rst包给客户端。结论:客户端发送完最后一个ack后,就认为连接建立,connect成功!
3,accept成功?这个更简单了,accept函数调用只是去accept队列中取出一个连接而已,对服务器而言,只要接收了客户端的ack(注意,不忽略不抛弃哦),状态变更为Established了,而不是accept调用成功才变成Established的。
4,tcp的backlog队列
linux在实现tcp协议栈的时候,采用了两个队列,syn和accept队列。
当接收了对端的syn后,将其放入syn队列;当接收了对端的ack后,将syn队列中的连接转移到accept队列。5,如果backlog队列满了,咋办?如果服务器端Established了,但突然客户端断网了,服务器进入半连接,咋办?如果客户端不停的发送syn包咋办?等等。。。很多问题。。这将会在我的
浅析TCP(上) – 曹东的文章 – 知乎专栏
中篇中详细介绍,敬请期待!