1

私はマルチクライアントサーバーを作成しようとしてきましたが、最終的には完全に機能しましたが、今やりたいことは、クライアントのアドレスを取得する代わりに、クライアントに名前を入力させることです。 「127.0.0.1: こんにちはみんな」の代わりに「ボブ: こんにちはみんな」。

Python docs の既製のサーバーとクライアントを使用しました。サーバーは次のとおりです。

import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):


    def handle(self):
        data = self.request[0].strip()
        name = self.request[0].strip()
        socket = self.request[1]
        print(name,"wrote:".format(self.client_address[0]))
        print(data)
        socket.sendto(data.upper(), self.client_address)

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = socketserver.UDPServer((HOST, PORT), MyUDPHandler)
    server.serve_forever()

そして、ここにクライアントがあります:

import socket
import sys

HOST, PORT = "localhost", 9999
data = "".join(sys.argv[1:])
name = "".join(sys.argv[1:])


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.sendto(bytes(name + "Bob", 'utf-8'), (HOST, PORT))
sock.sendto(bytes(data + "hello my name is Bob", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))

すべて正常に動作しますが、何らかの理由で、クライアントが接続するとサーバーでこれを取得します。

b'Bob'  wrote:
b'Bob'
b'hello my name is bob'  wrote:
b'hello my name is bob'

私はそれが次のようになりたい:

Bob wrote:
b'Hello my name is bob'

誰かが私を助けてくれることを願っています、ありがとう。

4

1 に答える 1

5

ここには複数の問題があります。


bytes1 つ目は、オブジェクトを直接印刷していることです。

print(name,"wrote:".format(self.client_address[0]))

そのため、 のb'Bob' wrote:代わりにを取得しますBob wrote:bytesPython 3 でオブジェクトを印刷すると、次のようになります。文字列にデコードしたい場合は、明示的に行う必要があります。

あらゆる場所でそれを行うコードがあります。通常はandコンストラクターよりもdecodeandencodeメソッドを使用する方がクリーンです。すでに使用している場合は、これを処理するさらに優れた方法がありますが、既存のスタイルに固執します。strbytesformat

print(str(name, "utf-8"), "wrote:".format(self.client_address[0]))

次に、なぜformatフォーマット パラメータのない文字列を呼び出しているのか、複数引数のprint関数とformat呼び出しを混在させているのかがわかりません。を取得しようとしているように見えますがself.client_address[0]、そうではありません。繰り返しますが、目的の出力には表示されません。そのため、format必要ない場合はその呼び出しを削除し、必要な{}場合はフォーマット文字列のどこかに a を追加してください。(おそらく、 もデコードしたいと思うでしょうclient_address[0]。)


次に、同じ値をnameandに格納しdataます。

data = self.request[0].strip()
name = self.request[0].strip()

したがって、後でこれを行うとき:

print(data)

…それはただ印刷するだけnameであり、また、それをデコードすることはありません。したがって、デコードの問題を修正しても、次のようになります。

Bob wrote:
Bob

…ただの代わりに:

Bob wrote:

dataこれを修正するには、変数とprint(data)呼び出しを取り除くだけです。


次に、2 つの別々のパケットを送信しています。1 つは で、もう 1 つは でnamedataそれぞれのパケットから両方を復元しようとしています。したがって、上記のすべてを修正したBobとしても、1 つのパケットを名前として取得しhello my name is bob、次のパケットを取得することになり、次のようになります。

Bob wrote:
hello my name is bob wrote:

これをステートフルにしたい場合は、実際に状態をどこかに保存する必要があります。あなたの場合、状態は信じられないほど単純で、これが特定のクライアントからの最初のメッセージであるかどうかを示すフラグにすぎませんが、それでもどこかに移動する必要があります。解決策の 1 つは、辞書を使用して新しい状態を各住所に関連付けることです。

すべてを一緒に入れて:

class MyUDPHandler(socketserver.BaseRequestHandler):
    def __init__(self, *args, **kw):
        self.seen = set()
        super().__init__(*args, **kw)

    def handle(self):
        data = self.request[0].strip()
        addr = self.client_address[0]
        if not addr in self.seen:
            print(str(data, "utf-8"), "wrote:")
            self.seen.add(addr)
        else:
            print(str(data, "utf-8"))
        socket.sendto(data.upper(), self.client_address)

一方、実際に必要なのは、最初のリクエストの名前をクライアントごとの状態として保存することであるように思われるため、将来のすべてのリクエストで再利用できます。それはほとんど簡単です。例えば:

class MyUDPHandler(socketserver.BaseRequestHandler):
    def __init__(self, *args, **kw):
        self.clients = {}
        super().__init__(*args, **kw)

    def handle(self):
        data = str(self.request[0].strip(), 'utf-8')
        addr = self.client_address[0]
        if not addr in self.clients:                
            print(data, "joined!")
            self.clients[addr] = data
        else:
            print(self.clients[addr], 'wrote:', data)
        socket.sendto(data.upper(), self.client_address)
于 2013-06-03T20:13:09.127 に答える