簡體   English   中英

穩健的連續 TCP 連接(python 插座)

[英]robust continuous TCP connection (python socket)

我的目標是在一台服務器和一個客戶端之間建立一個連續且健壯的 TCP連接。 如果一側出現故障,另一側應該等到它恢復。

我根據這個問題編寫了以下代碼(只要求連續但不健壯的 TCP 連接並且不處理保活問題)、 這篇文章和我自己的經驗。

我有兩個問題:

  1. 我怎樣才能使keepalive工作? 如果服務器死了,客戶端只有在嘗試send()后才能識別它——這在沒有KEEPALIVE選項的情況下也可以工作,因為這會導致連接重置。 是否有某種方法可以讓套接字為已死的連接或某些我可以定期檢查的 keepalive function 發送中斷?

  2. 這是處理連續 TCP 連接的可靠方法嗎? 擁有穩定、連續的 TCP 連接似乎是一個標准問題,但是,我找不到詳細介紹此問題的教程。 必須有一些最佳實踐

請注意,我可以在應用程序級別自行處理保持活動消息。 但是,由於 TCP 已經在傳輸層實現了這一點,因此最好依賴下層提供的這項服務。

服務器:

from socket import *
serverPort = 12000

while True:
    # 1. Configure server socket
    serverSocket = socket(AF_INET, SOCK_STREAM)
    serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    serverSocket.bind(('127.0.0.1', serverPort))
    serverSocket.listen(1)
    print("waiting for client connecting...")
    connectionSocket, addr = serverSocket.accept()
    connectionSocket.setsockopt(SOL_SOCKET, SO_KEEPALIVE,1)
    print(connectionSocket.getsockopt(SOL_SOCKET,SO_KEEPALIVE))
    print("...connected.")
    serverSocket.close() # Destroy the server socket; we don't need it anymore since we are not accepting any connections beyond this point.

    # 2. communication routine
    while True:
        try:
            sentence = connectionSocket.recv(512).decode()
        except ConnectionResetError as e:
            print("Client connection closed")
            break
        if(len(sentence)==0): # close if client closed connection
            break 
        else:
            print("recv: "+str(sentence))

    # 3. proper closure
    connectionSocket.shutdown(SHUT_RDWR)
    connectionSocket.close()
    print("connection closed.")

客戶端:

from socket import *
import time

while True:
    # 1. configure socket dest.
    serverName = '127.0.0.1'
    serverPort = 12000
    clientSocket = socket(AF_INET, SOCK_STREAM)
    try:
        clientSocket.setsockopt(SOL_SOCKET, SO_KEEPALIVE,1)
        clientSocket.connect((serverName, serverPort))
        print(clientSocket.getsockopt(SOL_SOCKET,SO_KEEPALIVE))
    except ConnectionRefusedError as e:
        print("Server refused connection. retrying")
        time.sleep(1)
        continue

    # 2. communication routine
    while(1):
        sentence = input('input sentence: ')
        if(sentence == "close"):
            break
        try:
            clientSocket.send(sentence.encode())
        except ConnectionResetError as e:
            print("Server connection closed")
            break

    # 3. proper closure
    clientSocket.shutdown(SHUT_RDWR)
    clientSocket.close()

我試圖盡可能少地保留這個例子。 但考慮到魯棒性的要求,它相對較長。

我還嘗試了一些套接字選項,如TCP_KEEPIDLETCP_KEEPINTVLTCP_KEEPCNT

謝謝!

我將嘗試回答這兩個問題。

  1. ...是否有某種方式可以使套接字為已死的連接發送中斷...

    我一個都不知道。 TCP_KEEPALIVE 僅嘗試維持連接。 如果網絡流上的任何設備出現超時,這將非常有用,因為它可以防止超時中止連接。 但是,如果連接由於任何其他原因(超時)而斷開,則 TCP_KEEPALIVE 無法執行任何操作。 基本原理是在必須交換某些內容之前,無需恢復已斷開的非活動連接。

  2. 這是處理連續 TCP 連接的可靠方法嗎?

    並不真地。

    穩健的方法是隨時准備連接因任何原因失敗。 因此,您應該准備好在發送消息時遇到錯誤(您的代碼是),如果發生這種情況,請嘗試重新打開連接並再次發送消息(您當前的代碼沒有)。 就像是:

     def connect(...): # establish and return a connection... return clientSocket clientSocket = connect(...) while True: ... while True: try: clientSocket.send(message) break except OSError: clientSocket = connect()...

無關:您的正常關機不正確。 發起者(使用shutdown的部分)不應立即關閉套接字,而是啟動讀取循環,並且僅在接收並處理完所有內容后才關閉。

我怎樣才能使keepalive工作? 如果服務器死了,客戶端只有在嘗試 send() 后才能識別它——這在沒有 KEEPALIVE 選項的情況下也可以工作,因為這會導致連接重置。

Keepalive 在服務器端或讀取端更有用。 這是一個狡猾的野獸。 除非您讀/寫,否則套接字根本不會通知您。 您可以查詢它的 state(盡管我不確定這對於標准 Python 是否可行)但這仍然不能解決通知問題。 無論如何,您需要定期檢查 state。

是否有某種方法可以讓套接字為已死的連接或某些我可以定期檢查的 keepalive function 發送中斷?

你聽說過兩將問題嗎? 沒有可靠的方法來檢測一側是否死亡。 然而,我們可以在 ping 和超時方面足夠接近。

請注意,我可以在應用程序級別自行處理保持活動消息。 但是,由於 TCP 已經在傳輸層實現了這一點,因此最好依賴下層提供的這項服務。

不,這不是更好。 如果出於任何原因,服務器和客戶端之間存在代理,那么 TCP 功能將不會為您提供幫助。 因為按照設計,它們只控制一個連接,而使用代理你至少有兩個連接。 您不應該根據底層傳輸 (TCP) 來考慮您的連接。 而是使用服務器(或客戶端或兩者)定期發送的 ping 命令創建您自己的協議以及超時。 通過這種方式,您可以確保對等方在周期間隔內處於活動狀態。

這是處理連續 TCP 連接的可靠方法嗎? 擁有穩定、連續的 TCP 連接似乎是一個標准問題,但是,我找不到詳細介紹此問題的教程。 必須有一些最佳實踐。

您將找不到涵蓋此內容的教程,因為該問題沒有解決方案。 大多數人通過 ping 和超時的組合來模擬“我還活着”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM