python套接字和socketserver

时间:2013-06-03 19:54:59

标签: python sockets client socketserver

我一直在努力创建一个多客户端服务器,我终于拥有并且它完美运行但我现在要做的是不是获取客户端地址,而是让客户端输入他们的名字然后程序会说" Bob:嗨伙计们"代替" 127.0.0.1:嗨伙计们#34;。

我使用了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'

我希望有人可以帮助我,谢谢。

1 个答案:

答案 0 :(得分:4)

你在这里遇到了很多问题。


首先是您直接打印bytes个对象:

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

这就是为什么你得到b'Bob' wrote:而不是Bob wrote:。在Python 3中打印bytes对象时,会发生这种情况。如果要将其解码为字符串,则必须明确地执行此操作。

你有代码可以在任何地方做到这一点。使用decodeencode方法通常比使用strbytes构造函数更简洁,如果您已经使用format,则可以使用更好的方法处理这个问题,但坚持你现有的风格:

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

接下来,我不确定你为什么在没有格式参数的字符串上调用format,或者为什么要混合多参数print函数和format调用一起。看起来你正试图获得self.client_address[0],但你并没有这样做。然后再次,您所需的输出不会显示它,所以...如果您不想要它,请删除format调用,如果您这样做,请在格式字符串中的某处添加{}。 (你也可能想要解码client_address[0]。)


接下来,您将相同的值存储在namedata

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

所以,当你以后这样做时:

print(data)

......那只是再次打印name - 再次,不解码它。所以,即使你解决了解码问题,你仍然会得到这个:

Bob wrote:
Bob

......而不只是:

Bob wrote:

要解决此问题,请删除data变量和print(data)来电。


接下来,您将发送两个单独的数据包,一个包含name,另一个包含data,但尝试从每个数据包中恢复。因此,即使您修复了上述所有问题,您将在一个数据包中获取Bob作为名称,并在下一个数据包中获得hello my name is bob,从而产生:

Bob wrote:
hello my name is bob wrote:

如果您希望这是有状态的,您需要在某处实际存储状态。在你的情况下,状态非常简单 - 只是一个标志,说明这是否是来自给定客户端的第一条消息 - 但它仍然必须去某个地方。一种解决方案是使用字典将新状态与每个地址相关联 - 尽管在这种情况下,由于状态是“之前看到的”或者根本没有,所以我们可以使用一个集合。

全部放在一起:

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)