我一直在努力创建一个多客户端服务器,我终于拥有并且它完美运行但我现在要做的是不是获取客户端地址,而是让客户端输入他们的名字然后程序会说" 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'
我希望有人可以帮助我,谢谢。
答案 0 :(得分:4)
你在这里遇到了很多问题。
首先是您直接打印bytes
个对象:
print(name,"wrote:".format(self.client_address[0]))
这就是为什么你得到b'Bob' wrote:
而不是Bob wrote:
。在Python 3中打印bytes
对象时,会发生这种情况。如果要将其解码为字符串,则必须明确地执行此操作。
你有代码可以在任何地方做到这一点。使用decode
和encode
方法通常比使用str
和bytes
构造函数更简洁,如果您已经使用format
,则可以使用更好的方法处理这个问题,但坚持你现有的风格:
print(str(name, "utf-8"), "wrote:".format(self.client_address[0]))
接下来,我不确定你为什么在没有格式参数的字符串上调用format
,或者为什么要混合多参数print
函数和format
调用一起。看起来你正试图获得self.client_address[0]
,但你并没有这样做。然后再次,您所需的输出不会显示它,所以...如果您不想要它,请删除format
调用,如果您这样做,请在格式字符串中的某处添加{}
。 (你也可能想要解码client_address[0]
。)
接下来,您将相同的值存储在name
和data
:
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)