簡體   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