[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;