首页 > 解决方案 > 套接字侦听()接受一个太多的连接

问题描述

我试图将 Python 服务器限制为只接受来自一个客户端的连接,但我注意到 Python 服务器总是接受一个太多的连接。这是服务器代码:

import socket 
import time

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(), 1234))
s.listen(0)
clientsocket, address = s.accept()
print(f"Connection from {address} has been established!")
while True:
    time.sleep(1000)
    clientsocket.send(bytes("Welcome to server 1!", "utf-8"))

我希望这一次只允许一个客户端连接,因为队列中不允许有任何客户端连接(s.listen(0))。但是,我发现此代码允许我在出现错误之前连接两个客户端。这是我的客户连接:

>>> import socket
>>> socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((socket.gethostname(), 1234))
>>> socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((socket.gethostname(), 1234))
>>> socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((socket.gethostname(), 1234))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it

第一个客户被接受,这是预期的。第二个客户端成功连接,这是我没想到的,因为服务器已经有一个连接并且队列中允许 0 个连接。在第三个客户端尝试连接并被拒绝之前,我们不会失败。

如果我们将listen()参数设置为 1,则允许 3 个连接(1 个当前连接,2 个在队列中)。如果我们将其增加到 2,则允许有 4 个连接(1 个当前连接,3 个在队列中)。这种模式仍在继续。

如何指定我的服务器应允许允许 1 个连接并且不在队列中保留任何连接?

标签: pythonsockets

解决方案


无论文档如何:

socket.listen([backlog])
使服务器接受连接。如果指定 backlog,则必须至少为 0(如果较低,则设置为 0);它指定在拒绝新连接之前系统将允许的未接受连接的数量。如果未指定,则选择默认的合理值。

测试表明最小值是1针对未接受的连接,而不是backlog + 1. 这可能取决于操作系统。我使用的是 Windows 10。注意我不接受下面的任何连接,只是连接直到它们被拒绝。

In [1]: from socket import *
   ...: for backlog in range(-1,6):
   ...:     s=socket()
   ...:     s.bind(('',5000))
   ...:     s.listen(backlog)
   ...:     c=[]
   ...:     try:
   ...:         while True:
   ...:             a=socket()
   ...:             a.connect(('localhost',5000))
   ...:             c.append(a)
   ...:     except ConnectionRefusedError:
   ...:         print(f'{backlog=} successful_connections={len(c)}')
   ...:
backlog=-1 successful_connections=1
backlog=0 successful_connections=1
backlog=1 successful_connections=1
backlog=2 successful_connections=2
backlog=3 successful_connections=3
backlog=4 successful_connections=4
backlog=5 successful_connections=5

这是有道理的。您需要至少有一个未接受的连接排队,否则将一事无成.accept()

如果您只想要一个接受的连接,请.accept()在接受另一个之前连续调用并关闭它。如果客户端连接、发送查询并且在设定的时间内没有得到响应,则客户端可以使用超时。


推荐阅读