socket编程:backlog值对listen连接状态的影响

1. 概述

对于TCP服务器,使用bind绑定一个地址和端口,然后使用listen(backlog)在这个socket上监听用户的连接请求。其中,backlog参数的大小,决定了TCP服务器的连接请求队列大小,进一步影响客户端连接请求的成功与否。
本文档介绍通过实验的方式获得不同backlog参数值的不同影响。实验使用Python语言。

2 socket连接建立过程

2.1 服务器监听端口

通常需要以下三个步骤:
sock = socket.socket()    #创建socket对象:
sock.bind((“”, 7890))    #将socket绑定到指定地址和端口上
sock.listen(5)    #使socket监听指定地址和端口


然后,调用accept方法获得一个客户端连接请求。
client_sock, addr = sock.accept()


2.2 客户端建立连接

通常执行以下两个步骤:
sock = socket.socket()    #创建socket对象
sock.connect((“”, 7890))    #请求连接指定地址和端口


2.3 服务器的连接请求队列

系统为正等待连接请求的TCP服务程序,维护一个固定长度的连接队列。这个队列中的连接是已经被TCP接收(已经完成三次握手),但是还没有被应用程序接收(调用accept函数)
队列的长度就是服务器调用listen时指定的。但指定的数值并不直接就是队列的长度,通常是需要经过公式转换的。
如下图所示,当客户连接请求到达时,系统底层处理这个请求,TCP握手成功完成后,将其放入连接队列,等待服务程序accept。
 

3 实验

3.1 实验步骤

首先,服务器端执行以下步骤:
1. 绑定地址和端口,并监听,等待客户端请求
2. 获取一个连接请求,进入睡眠10秒,
3. 接收客户端数据
4. 重复步骤2,3。


其次,客户端执行以下步骤:
1. 创建socket,请求连接服务器。
2. 等待连接成功,发送数据。
3. 关闭连接。


最后,同时启动多个客户端。由于服务器接收一个请求后,进入睡眠,当客户端数量达到一定数值时,将超过连接队列的长度。观察在这种情况下,不同客户端的连接状态,以及对应的行为。


3.2 实验代码

Server.py代码如下:
  1 import socket
  2 import time
  3 
  4 def main():
  5     sock = socket.socket()
  6     host = ""
  7     port = 7890
  8     sock.bind((host, port))
  9     sock.listen(0)
 10 
 11     sleep_sec = 10
 12     while True:
 13         client_sock, addr = sock.accept()
 14         print "New client:", client_sock.getpeername()
 15         time.sleep(sleep_sec)
 16 
 17         data = client_sock.recv(1024)
 18         print "received:", len(data)
 19 
 20 if __name__ == '__main__':
 21     main()


client.py代码如下:
  1 import socket
  2 import time
  3 
  4 def main():
  5     host = ""
  6     port = 7890
  7     sock = socket.socket()
  8     sock.connect((host, port))
  9     print "connect successfully."
 10 
 11     sent_byte = sock.send(' '*1024)
 12     print "sent byte:", sent_byte
 13     sock.close()
 14 
 15 if __name__ == '__main__':
 16     main()

4 实验结果

4.1 超出队列长度的客户端握手失败

当启动的客户端数量超过队列长度时,客户端与服务器端的连接实际上是没有建立起来的。通过命令“netstat -tuan |grep 7890”观察连接建立情况,如下所示。同时开启5个客户端程序,只有3个是与服务器建立连接的,它们的端口号是40695,40696,40697。而另外两个客户端与服务器的三次握手处于SYN_RECV状态,它们的端口号是40698,40699。
[root@roy network]# netstat -tuan |grep 7890
tcp        0      0 0.0.0.0:7890                0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:7890              127.0.0.1:40699             SYN_RECV    
tcp        0      0 127.0.0.1:7890              127.0.0.1:40698             SYN_RECV    
tcp        0   1024 127.0.0.1:40698             127.0.0.1:7890              ESTABLISHED 
tcp     1024      0 127.0.0.1:7890              127.0.0.1:40695             ESTABLISHED 
tcp        0      0 127.0.0.1:40696             127.0.0.1:7890              ESTABLISHED 
tcp        0      0 127.0.0.1:40695             127.0.0.1:7890              ESTABLISHED 
tcp        0      0 127.0.0.1:40697             127.0.0.1:7890              ESTABLISHED 
tcp     1024      0 127.0.0.1:7890              127.0.0.1:40697             ESTABLISHED 
tcp        0   1024 127.0.0.1:40699             127.0.0.1:7890              ESTABLISHED 
tcp     1024      0 127.0.0.1:7890              127.0.0.1:40696             ESTABLISHED

但是,这里应该注意到客户端认为的连接状态是成功建立的,因为从客户端端口到服务器端口的连接都是处于ESTABLISHED的。这将导致客户端程序执行connect时是成功返回的,并继续下一步的动作,向服务器发送数据。由于数据的发送是交给系统底层完成的,当客户端执行send时,数据将传送给系统底层。如果系统底层可以接收所有数据,则客户程序认为发送成功并返回。这点通过客户端执行结果,可以得到验证。所有客户端都是立即完成,并输出以下信息:
connect successfully.
sent byte: 1024

实际的情况是什么样的呢?通过命令“tcpdump -i lo”观察数据的传送。从以下数据可以看出,服务器程序实际上并没有与客户端程序建立连接,而且数据传输也没有真正完成。
18:20:06.566665 IP localhost.localdomain.40695 > localhost.localdomain.7890: Flags [S], seq 1216469746, win 32792, options [mss 16396,sackOK,TS val 33817848 ecr 0,nop,wscale 7], length 0
18:20:06.566681 IP localhost.localdomain.7890 > localhost.localdomain.40695: Flags [S.], seq 210636462, ack 1216469747, win 32768, options [mss 16396,sackOK,TS val 33817848 ecr 33817848,nop,wscale 7], length 0
18:20:06.566691 IP localhost.localdomain.40695 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33817848 ecr 33817848], length 0    注:40695与7890三次握手完成。
18:20:06.566724 IP localhost.localdomain.40695 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33817848 ecr 33817848], length 1024
18:20:06.566729 IP localhost.localdomain.7890 > localhost.localdomain.40695: Flags [.], ack 1025, win 272, options [nop,nop,TS val 33817848 ecr 33817848], length 0   注:40695与7890数据传输完成。
18:20:07.958287 IP localhost.localdomain.40696 > localhost.localdomain.7890: Flags [S], seq 35163015, win 32792, options [mss 16396,sackOK,TS val 33819240 ecr 0,nop,wscale 7], length 0
18:20:07.958303 IP localhost.localdomain.7890 > localhost.localdomain.40696: Flags [S.], seq 3952522703, ack 35163016, win 32768, options [mss 16396,sackOK,TS val 33819240 ecr 33819240,nop,wscale 7], length 0
18:20:07.958314 IP localhost.localdomain.40696 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33819240 ecr 33819240], length 0   注:40696与7890三次握手完成。
18:20:07.958350 IP localhost.localdomain.40696 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33819240 ecr 33819240], length 1024
18:20:07.958355 IP localhost.localdomain.7890 > localhost.localdomain.40696: Flags [.], ack 1025, win 272, options [nop,nop,TS val 33819240 ecr 33819240], length 0   注:40696与7890数据传输完成。
18:20:09.192664 IP localhost.localdomain.40697 > localhost.localdomain.7890: Flags [S], seq 3608836259, win 32792, options [mss 16396,sackOK,TS val 33820474 ecr 0,nop,wscale 7], length 0
18:20:09.192679 IP localhost.localdomain.7890 > localhost.localdomain.40697: Flags [S.], seq 685598874, ack 3608836260, win 32768, options [mss 16396,sackOK,TS val 33820474 ecr 33820474,nop,wscale 7], length 0
18:20:09.192689 IP localhost.localdomain.40697 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33820474 ecr 33820474], length 0   注:40697与7890三次握手完成。
18:20:09.192720 IP localhost.localdomain.40697 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33820474 ecr 33820474], length 1024
18:20:09.192725 IP localhost.localdomain.7890 > localhost.localdomain.40697: Flags [.], ack 1025, win 272, options [nop,nop,TS val 33820474 ecr 33820474], length 0   注:40697与7890数据传输完成。
18:20:11.029180 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [S], seq 2974930268, win 32792, options [mss 16396,sackOK,TS val 33822311 ecr 0,nop,wscale 7], length 0
18:20:11.029194 IP localhost.localdomain.7890 > localhost.localdomain.40698: Flags [S.], seq 1793008575, ack 2974930269, win 32768, options [mss 16396,sackOK,TS val 33822311 ecr 33822311,nop,wscale 7], length 0
18:20:11.029205 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33822311 ecr 33822311], length 0  注:40698认为完成三次握手,开始发送数据
18:20:11.029235 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33822311 ecr 33822311], length 1024
18:20:11.234022 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33822516 ecr 33822311], length 1024
18:20:11.644014 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33822926 ecr 33822311], length 1024
18:20:12.464030 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33823746 ecr 33822311], length 1024   注:40698不断地尝试发送数据,但是一直得不到确认。
18:20:12.630848 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [S], seq 636250882, win 32792, options [mss 16396,sackOK,TS val 33823912 ecr 0,nop,wscale 7], length 0
18:20:12.630869 IP localhost.localdomain.7890 > localhost.localdomain.40699: Flags [S.], seq 3213239187, ack 636250883, win 32768, options [mss 16396,sackOK,TS val 33823912 ecr 33823912,nop,wscale 7], length 0
18:20:12.630880 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33823912 ecr 33823912], length 0   注:40699认为完成三次握手,开始发送数据
18:20:12.630906 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33823912 ecr 33823912], length 1024
18:20:12.835057 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33824117 ecr 33823912], length 1024
18:20:13.245181 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33824527 ecr 33823912], length 1024
18:20:14.065176 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33825347 ecr 33823912], length 1024   注:40699不断地尝试发送数据,但是一直得不到确认。


18:20:14.104004 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33825386 ecr 33822311], length 1024
18:20:15.429005 IP localhost.localdomain.7890 > localhost.localdomain.40698: Flags [S.], seq 1793008575, ack 2974930269, win 32768, options [mss 16396,sackOK,TS val 33826711 ecr 33825386,nop,wscale 7], length 0
18:20:15.429031 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33826711 ecr 33826711,nop,nop,sack 1 {0:1}], length 0
18:20:15.705011 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33826987 ecr 33823912], length 1024
18:20:16.229023 IP localhost.localdomain.7890 > localhost.localdomain.40699: Flags [S.], seq 3213239187, ack 636250883, win 32768, options [mss 16396,sackOK,TS val 33827511 ecr 33826987,nop,wscale 7], length 0
18:20:16.229048 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33827511 ecr 33827511,nop,nop,sack 1 {0:1}], length 0
18:20:17.384006 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33828666 ecr 33826711], length 1024
18:20:18.985134 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33830267 ecr 33827511], length 1024
18:20:21.829012 IP localhost.localdomain.7890 > localhost.localdomain.40698: Flags [S.], seq 1793008575, ack 2974930269, win 32768, options [mss 16396,sackOK,TS val 33833111 ecr 33828666,nop,wscale 7], length 0
18:20:21.829038 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33833111 ecr 33833111,nop,nop,sack 1 {0:1}], length 0
18:20:22.628995 IP localhost.localdomain.7890 > localhost.localdomain.40699: Flags [S.], seq 3213239187, ack 636250883, win 32768, options [mss 16396,sackOK,TS val 33833911 ecr 33830267,nop,wscale 7], length 0
18:20:22.629018 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [.], ack 1, win 257, options [nop,nop,TS val 33833911 ecr 33833911,nop,nop,sack 1 {0:1}], length 0
18:20:23.944009 IP localhost.localdomain.40698 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33835226 ecr 33833111], length 1024
18:20:25.545035 IP localhost.localdomain.40699 > localhost.localdomain.7890: Flags [P.], seq 1:1025, ack 1, win 257, options [nop,nop,TS val 33836827 ecr 33833911], length 1024


4.2 不同backlog对应的队列长度

 


5.总结

客户端connect成功返回时,并不表示与服务端的连接已经真正建立。Send发送数据成功返回也不表示服务器端已经成功接收了。编程时应该注意到这两点。
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值