天天看点

tcp/listen/backlog

这是在一个电脑上进行测试后的结果截图。

tcp/listen/backlog
tcp/listen/backlog
tcp/listen/backlog

对于这个结果我想到的第一个相关的就是listen(int sockfd,int backlog)中的backlog参数设置的是5(backlog参数的典型值),backlog参数提示内核监听队列的最大长度如果超过backlog(在内核版本2.2之前的Linux中,backlog参数是指所有处于半连接状态‘SYN_RCVD’和完全连接状态‘ESTABLISHED’的socket的上限。但自内核2.2之后,他只表示处于完全连接的socket的socket的上限),服务器将不受理新的客户连接,客户也将收到ECONNREFUSED(连接被服务器拒绝)错误信息。所以我理所当然的以为只有5个客户端可以与服务器完成连接(三次握手),但是当我一次又一次的启动一个客户端都可以完成连接,然后我百度了一下,看了这样一句话“说了如果开启了syncookies 忽略listen的第二个参数。 ”然后我查看了下结果是1说明syncookies已启用,

① 意思就是5这个数字是被忽略的,那个backlog究竟是多少?

② 究竟可以连接多少个客户端(或者说能连接多少个客户端和谁有关)?

③ accept成功的客户端还会待在accept queue(已经完成三次握手的监听队列)?“服务器处于Listen状态时收到客户端SYN报文时放入半连接队列中,即SYN queue(服务器端口状态为:SYN_RCVD)。TCP的连接状态从服务器(SYN+ACK)响应客户端后,到客户端的ACK报文到达服务器之前,则一直保留在半连接状态中;当服务器接收到客户端的ACK报文后,该条目将从半连接队列搬到全连接队列尾部,即 accept queue (服务器端口状态为:ESTABLISHED)。因为accept queue 已满,系统会直接丢弃后续ACK请求(后续就不存在完成三次握手的连接),那么客户端connect()是在收到服务器端SYN+ACK时返回的那么客户端的连接是否成功?”

1.然后呢就会发现我之前的理解是错误的(客户端连接的个数与backlog有个毛线关系),backlog参数的值不能超过/proc/sys/net/core/somaxconn(我电脑上的这个值是128),(backlog在这两个之间取小)而backlog也只是决定了accept queue大小, 内核参数

/proc/sys/net/ipv4/tcp_max_syn_backlog(我电脑上的这个值是512)决定syn queue的大小。那么第一个问题也算是解决了。

2.限制客户端连接个数的因素操作系统全局文件描述符的数量以及内存的大小。(目前还没测试)

3.至于这三个问题我觉得我能想到也是挺奇葩的,但还是有一点疑惑,如果这个时候服务器达到可连接个数的最大上限,那么是不是说后续的连接就会导致accept queue和syn queue都会发生“队满”,先假设之前的连接都保持着,那么后续的这些未完成的连接该不该存在,accept queue中的连接不能通过accept生成负责该连接的文件描述符。那么这个时候服务器能不能收到客户端发送的数据?按说这个时候服务器和客户端都是处于ESTABLISHED状态,服务器应该是能收到客户端的数据。但是却没人来接手这些数据。那么recv会不会异常?而处于syn queue中的半连接完成不了三次握手,服务器会将客户端传来的ACK报文丢弃或忽视,客户端误以为连接已建立,开始调用等待至超时;服务器则等待ACK超时,会重传SYN+ACK 给客户端,重传次数受限 proc/net/ipv4/tcp_synack_retries ,默认为5,表示重发5次,每次等待30~40秒,即半连接默认时间大约为180秒,该参数可以在tcp被洪水攻击时临时启用这个参数。那么就是说syn queue会在此之后丢弃它,然后一直在更新?也就是在此之后要么服务器拒绝连接请求,要么就是syn queue丢弃一个放入一个然后发生和前面一样的事情等待着可以进入accept queue中,被accept调用生成一个文件描述符建立一个完整的连接。

然后就是对测试结果的分析:我的服务器并没有因为accept不了而崩溃,而是在一次又一次的打开一个新的终端的情况下出现以下提示:

There was an error creating the child process for this terminal failed to fork (Resource temporarily unavailable)

创建此终端的子进程失败时出错(资源暂时不可用)

然后就是测试数据:截图中C = *是accept()成功后返回的文件描述符,,每一个tcp连接都有一个唯一的C负责与客户端的通信。后面紧接着就是客户端对应的ip和port,规律性很强。(大概也就是从中了解一下端口的分配和文件描述符的分配)