0%

tcp之不accept

[TOC]

概述

其实如果 tcp server 端不 accept 就和线上因为 server 端阻塞,没有 accept 是一样的。

结论是连接能够建立,但是没有accept函数调用,那么所有的已建立好的连接都会堵塞在全连接队列里,当队列满了以后,就会拒绝建立连接了。

accept 函数调用

The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection request on the queue of pending connections for the listen‐ing socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. The newly created socket is not in the listening state. The original socket sockfd is unaffected by this call.

accept函数的作用是从”pending connections”队列中取出第一个连接,并生成一个新的连接套接字返回给应用程序,用于进行读写操作,并且不会影响原有的监听套接字;

两种状态的连接

具体来说,在协议栈的实现中,根据连接的状态划分出了两种类型:

  • incomplete connection (半开连接,处于SYN_RECV状态,还没有收到最后一个ACK)
  • completely established socket (已完成连接,处于ESTABLISHED状态)

而listen函数的backlog参数指定的是已完成连接队列的最大长度。

连接满了怎么办

当全连接队列已经满了,继续尝试建立连接。可以看到,之后的连接都停留在SYN_RECV状态,抓包可以看到,server端收到了client的最后一个ACK,但仍然会重传SYN/ACK,通过查看协议栈代码可知,此时的行为与sysctl_tcp_abort_on_overflow(/proc/sys/net/ipv4/tcp_abort_on_overflow)的值有关:

  • 当sysctl_tcp_abort_on_overflow为0时(default):compeletly established queue满了之后服务器会丢掉第三个ACK;
  • 否则,直接发RST;

参考

由“socket程序listen之后不accept“说起