繁体   English   中英

如何限制套接字的连接数并在客户端触发超时(Python)

[英]How to limit the number of connections to a socket and trigger timeout on client (Python)

如何设置服务器套接字一次可以接受的连接数限制? 我希望能够设置最大连接数,然后一旦达到该限制,客户端连接的任何进一步尝试都将导致超时。 到目前为止,我已经尝试过这样的服务器:

sock = socket.socket()
sock.setblocking(0)
sock.bind(address)
sock.listen(0)

connections = []

while True:
    readable, writable, exceptional = select.select([sock], [], [])

    if readable and len(connections) < MAX_CONNECTIONS:
        connection, client_address = s.accept()
        connections.append(connection)
        # Process connection asynchronously

并为客户:

try:
    sock = socket.create_connection(self.address, timeout=TIMEOUT)
    sock.settimeout(None)
    print "Established connection."
except socket.error as err:
    print >> sys.stderr, "Socket connection error: " + str(err)
    sys.exit(1)

# If connection successful, do stuff

由于程序其余部分的结构,我选择在服务器上使用非阻塞套接字,我不想改变它。 现在,即使达到限制并且服务器停止接受它们,客户端也能够连接到服务器。 我该如何解决这个问题? 谢谢。

我相信这里可能会对select()产生轻微的误解。 根据联机帮助页, select()返回“已准备好进行某类IO操作”的文件描述符,其中ready表示“可以执行相应的IO操作而不会阻塞”。 侦听套接字上的相应IO操作是accept() ,如果操作系统已经为您进行了完全的TCP握手,则只能在不阻塞的情况下执行,否则您可能会阻止等待客户端的最终ACK。

这意味着只要侦听套接字打开,操作系统就会接受连接,即使应用程序没有处理。 如果要在设定的数字后拒绝连接,则基本上有两个选项:

  • 接受后直接接受并关闭。
  • 达到极限时关闭侦听套接字,完成后重新打开。

第二个选项更复杂,需要使用SO_REUSEADDR选项,这可能不适合您的情况。 它可能也不适用于所有操作系统,尽管它似乎在Linux上可靠运行。

这是第二个解决方案的快速草图(因为第一个解决方案非常简单)。

def get_listening_socket():
    sock = socket.socket()
    sock.setblocking(0)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('0.0.0.0', 5555))
    sock.listen(0)
    return sock

sock = get_listening_socket()

LIMIT = 1
conns = {sock}
while True:
    readable, writable, exceptional = select.select(conns, [], [])
    if sock in readable: # new connection on the listening socket
        conn, caddr = sock.accept()
        conns.add(conn)
        if len(conns) > LIMIT: # ">" because "sock" is also in there
            conns.remove(sock)
            sock.close()
    else: # reading from an established connection
        for c in readable:
            buf = c.recv(4096)
            if not buf:
                conns.remove(c)
                sock = get_listening_socket()
                conns.add(sock)
            else:
                print("received: %s" % buf)

但是,您可能想重新考虑为什么要首先执行此操作。 如果仅仅是关于在服务器上保存一些内存,那么你可能会过度优化,而应该考虑使用syn-cookies。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM