4

背景
私は、データへの同時接続とエコーバックを許可しようとしている単純なソケットサーバーのセットアップを持っています。クライアント側はいくつかのスレッドを起動し、それぞれがサーバーへの独自の接続を確立します。これは、socket.send() 呼び出しでは正常に機能しますが、後続のすべての呼び出しで、「ピアによる接続のリセット」または「パイプの破損」が発生します。リセットと壊れたパイプを切り替える変更が見つからないことに注意してください。ここで解決策を探しましたが、何を検索すればよいかわからないのではないかと心配しています。

これについて間違った方法で行っていますか、それともセットアップで何かを見落としていますか?

サーバ

import SocketServer

class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
        print "{} wrote: {}\n".format(self.client_address[0], self.data)
        self.request.send(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

クライアント

import socket
import sys
import threading
import time

HOST, PORT = "localhost", 9999
def create_client():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        cur_thread = threading.current_thread()
        sock.connect((HOST, PORT))
        for x in range(55):
            msg = "{}: {}\n".format(cur_thread.name, str(x))
            # Connect to server and send data
            print cur_thread.name + ": sending message\n"
            sock.send(msg)
            # Receive data from the server and shut down
            received = sock.recv(2048)
            print "RX:" + received
    finally:
        cur_thread = threading.current_thread()
        response = "{}: Closing!\n".format(cur_thread.name)
        print response
        sock.close()

if __name__ == "__main__":
    print "testing single thread"
    #create_client()
    print "starting threads"
    client_1 = threading.Thread(target=create_client)
    client_1.daemon = True
    client_1.start()
    client_2 = threading.Thread(target=create_client)
    client_2.daemon = True
    client_2.start()

    time.sleep(20)
4

1 に答える 1

8

handleソケットから戻ると、閉じられます。while ループを使用し、handlewhen のみから戻りself.data == ''ます。recvクライアントが接続を閉じると、0 バイトが返されます。またstrip()、戻り値をテストするまで結果を取得しないでください。そうしないと、偽のクローズが発生する可能性があります。最後に、使用ThreadingTCPServerまたはサーバーは一度に 1 つの接続しか処理できません。

例:

import SocketServer

class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        while True:
            self.data = self.request.recv(1024)
            if self.data == '':
                break
            self.data = self.data.strip()
            print "{} wrote: {}\n".format(self.client_address[0], self.data)
            self.request.send(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

また、send()はメッセージのすべてのバイトを送信するとは限らないためsendall()、戻り値を使用または確認してください。 recv()トリッキーな場合もあります。TCP/IP はストリーミング プロトコルであり、メッセージ境界の概念がないため、完全なメッセージを受信したことを確認するプロトコルを実装する必要があります。10000 バイトを送信してそれ未満を受信することは可能であり、メッセージ全体を取得するには複数回の受信が必要になります。2 つの送信と受信の両方を 1 回の受信で行うことも、1 つの送信と別の一部のすべてを送信することも可能です。\nあなたの例では、単純なプロトコルの場合、メッセージに が含まれるまですべての受信をバッファリングするだけです。

于 2011-12-17T18:19:46.573 に答える