网络---tcp建链研究

正在listen的socket收到connect后,没有accept时,listen链路recvQ非0,此时新socket已经建链,而且是ESTABLISHED状态,抓包可以确认tcp自动完成3次握手的:

tcp        1      0 10.47.160.67:8020       0.0.0.0:*               LISTEN     

tcp        0      0 10.47.160.67:8020       10.47.160.95:39057      ESTABLISHED

这时客户端向新建链路发送消息后,会看到链路的recvQ有数据等待被取走:

tcp        1      0 10.47.160.67:8020       0.0.0.0:*               LISTEN     

tcp      604      0 10.47.160.67:8020       10.47.160.95:39057      ESTABLISHED

这时服务端accept()只是从listen队列里取出一个socket:

tcp        0      0 10.47.160.67:8020       0.0.0.0:*               LISTEN     

tcp      604      0 10.47.160.67:8020       10.47.160.95:39057      ESTABLISHED

服务端新链接执行recv()就可以从链路读取指定长度数据:

tcp        0      0 10.47.160.67:8020       0.0.0.0:*               LISTEN     

tcp      504      0 10.47.160.67:8020       10.47.160.95:39057      ESTABLISHED

如果服务端没有及时accept,监听socket上会积压,LISTEN链路上recvQ队列的积压是tcp的已建链队列数据,又称accept队列,等待服务端accept取走;SYN_RECV链接是半链接状态,半链接队列、accept队列的长度计算见下面伪代码。

tcp       11      0 10.47.160.67:8020       0.0.0.0:*               LISTEN      

tcp        0      0 10.47.160.67:8020       10.47.160.95:56733      SYN_RECV   

如果此时客户端发送一个FIN包,recvQ多了一个字节,而且服务端状态变为CLOSE_WAIT;

tcp        0      0 10.47.160.67:8020       0.0.0.0:*               LISTEN     

tcp      505      0 10.47.160.67:8020       10.47.160.95:39057      CLOSE_WAIT

这时服务执行recv()读取全部数据后,数据被取走,但没有返回失败:

tcp        0      0 10.47.160.67:8020       0.0.0.0:*               LISTEN     

tcp        0      0 10.47.160.67:8020       10.47.160.95:39057      CLOSE_WAIT 

这时服务端是close_wait,客户端是FIN_WAIT2,服务再次执行recv(),返回0,表示收到FIN包。

tcp        0      0 10.47.160.67:8020       0.0.0.0:*               LISTEN 

补充:如果发送方应用进程发送完数据后,立即发送一个RST包,这时协议栈里积压的数据会丢弃,接收方无法接收完整数据库,而是直接断链。

 

listen(backlog)

{

somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;

if ((unsigned)backlog > somaxconn)     

backlog = somaxconn;

inet_listen->inet_csk_listen_start(sk, backlog);

nr_table_entries = min( backlog, sysctl_max_syn_backlog);

nr_table_entries = max( nr_table_entries, 8);

nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);  // nr_table_entries 是request sock queue 的长度

sk->sk_max_ack_backlog = backlog; //这里确定了accept queue的长度。

}

backlog为listen()的第二个参数;

sysctl_max_syn_backlog为系统配置net.ipv4.tcp_max_syn_backlog;

sock_net(sock->sk)->core.sysctl_somaxconn为系统配置net.core.somaxconn;

 

你可能感兴趣的:(网络---tcp建链研究)