listen,accept的思考

在网络编程调用listen,accept的时候,我时不时会有这样的疑问:究竟listen函数的第二个参数指的是什么,虽然大致知道是连接队列的意思。但是面对错综复杂的网络环境,特别是在高并发编程中,完全搞清楚他的真实含义很有必要,不至于担心连接跟不上,导致连接这块出问题,至少出了问题能做到心中有数。

服务器建立socket连接要调用listen监听socket。listen的第二个参数backlog是指连接队列的大小。关于这个值,我们一般会忽视他,填写一个小的整数,例如5即可。不过想要深入研究网络编程,还是搞清楚这些细节为好。究竟这个参数backlog是什么意思呢?我们还是找男人吧,man:

The  behavior  of  the  backlog  argument on TCP sockets changed with Linux 2.2.  Now it specifies the queue
       length for completely established sockets waiting to be accepted, instead of the number of  incomplete  con‐
       nection   requests.    The   maximum   length  of  the  queue  for  incomplete  sockets  can  be  set  using
       /proc/sys/net/ipv4/tcp_max_syn_backlog.  When syncookies are enabled there is no logical maximum length  and

       this setting is ignored.  See tcp(7) for more information.

意思是说这个参数的意思自从linux 2.2之后就有所改变了,表示全连接队列的大小,而不是半连接队列的大小了。而半连接的大小则是在系统文件里定义的(查看为128)。

什么是全连接,什么是半连接呢?这个涉及三次握手的过程。

当服务器收到客户端调用connnect发起连接syn时,syn会进入syn队列中,此时服务器进入syn-rcvd状态,即半连接状态,然后给客户端回复syn-ack。客户端收到syn-ack之后,再次给服务器发送ack,connect即返回成功,注意,此时连接并未完全建立。只有当服务器再次收到ack只后,连接才算完成。

服务器再次收到ack后,就会从半连接队列中取出对应的连接,并放入全连接队列中。backlog这个参数就是指全队列的大小。accepte函数就是从全连接队列中取出一个连接,如果accept调用不及时,而客户端又在一直连接,就会导致这个全连接队列变满。示意图如下:


全队列变满之后,客户端连接connect任会成功,为什么?

前面所说,connect是收到服务器的syn-ack并发送ack就会成功,此时连接并未完全建立。虽然全连接队列已满,并不代表半连接队列已满或者说停滞不再接收连接。

如果全连接已满,而客户端还一直不停在连接,此时服务器端会如何处理呢?我做了如下实验:

设置backlog为8,客户端绑定固定递增端口不停的在连接,然后用netstat命令查看,发现服务器ESTABLISHED状态始终为9,而SYN_RECV状态为8,且SYN_RECV状态的端口一直在变,应该是最新的客户端端口值。


从以上结果中,我的推测是半连接的队列的大小其实全也受全连接队列大小影响,通过结果目测他们的值一样(这里应该保证不会大于半连接的最大值)。队列满后,服务器仍然可以接收连接,但是新的连接会覆盖已有的半连接队列,这样导致旧有连接会失败。而且新的连接明显会延时,因为客户端大概会每隔1s钟才会返回成功。


参考:

https://blog.csdn.net/russell_tao/article/details/9111769

https://blog.csdn.net/he_jian1/article/details/40787269

https://blog.csdn.net/zhangskd/article/details/16987637




猜你喜欢

转载自blog.csdn.net/zxm342698145/article/details/80946872
今日推荐