python套接字和socketserver
我一直在尝试制作一个多客户端服务器,我终于做到了,它工作得很好,但我现在想做的是,让客户端输入他们的名字,然后程序会说“Bob:Hi guys”,而不是“127.0.0.1:Hi guys” 我使用了python文档中预先制作的服务器和客户端。 这是服务器:python套接字和socketserver,python,sockets,client,socketserver,Python,Sockets,Client,Socketserver,我一直在尝试制作一个多客户端服务器,我终于做到了,它工作得很好,但我现在想做的是,让客户端输入他们的名字,然后程序会说“Bob:Hi guys”,而不是“127.0.0.1:Hi guys” 我使用了python文档中预先制作的服务器和客户端。 这是服务器: import socketserver class MyUDPHandler(socketserver.BaseRequestHandler): def handle(self): data = self.re
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'
我希望有人能帮助我,谢谢。你这里有很多问题
第一个是直接打印
字节
对象:
print(name,"wrote:".format(self.client_address[0]))
这就是为什么b'Bob写了:而不是Bob写的:。在Python3中打印bytes
对象时,会发生这种情况。如果要将其解码为字符串,则必须显式地执行此操作
你的代码到处都是这样的。使用解码
和编码
方法通常比使用str
和字节
构造函数更干净,如果您已经在使用格式
的话,还有更好的方法来处理这个问题,但要坚持您现有的风格:
print(str(name, "utf-8"), "wrote:".format(self.client_address[0]))
接下来,我不知道为什么要在没有格式参数的字符串上调用
format
,或者为什么要将多参数print
函数和format
调用混合在一起。看起来您正在尝试获取self.client\u地址[0]
,但您没有这样做。同样,您所需的输出没有显示它,因此…只要删除该format
调用即可。如果不需要,请在格式字符串中的某个位置添加一个{}
。(您可能还需要解码客户端地址[0]
。)
接下来,在
名称
和数据
中存储相同的值:
data = self.request[0].strip()
name = self.request[0].strip()
因此,当您稍后执行此操作时:
print(data)
…那只是一次又一次地打印名称
,而没有对其进行解码。因此,即使您解决了解码问题,您仍然会得到以下结果:
Bob wrote:
Bob
…而不仅仅是:
Bob wrote:
要解决这个问题,只需去掉data
变量和print(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)
你这里有很多问题
第一个是直接打印
字节
对象:
print(name,"wrote:".format(self.client_address[0]))
这就是为什么b'Bob写了:而不是Bob写的:。在Python3中打印bytes
对象时,会发生这种情况。如果要将其解码为字符串,则必须显式地执行此操作
你的代码到处都是这样的。使用解码
和编码
方法通常比使用str
和字节
构造函数更干净,如果您已经在使用格式
的话,还有更好的方法来处理这个问题,但要坚持您现有的风格:
print(str(name, "utf-8"), "wrote:".format(self.client_address[0]))
接下来,我不知道为什么要在没有格式参数的字符串上调用
format
,或者为什么要将多参数print
函数和format
调用混合在一起。看起来您正在尝试获取self.client\u地址[0]
,但您没有这样做。同样,您所需的输出没有显示它,因此…只要删除该format
调用即可。如果不需要,请在格式字符串中的某个位置添加一个{}
。(您可能还需要解码客户端地址[0]
。)
接下来,在
名称
和数据
中存储相同的值:
data = self.request[0].strip()
name = self.request[0].strip()
因此,当您稍后执行此操作时:
print(data)
…那只是一次又一次地打印名称
,而没有对其进行解码。因此,即使您解决了解码问题,您仍然会得到以下结果:
Bob wrote:
Bob
…而不仅仅是:
Bob wrote:
要解决这个问题,只需去掉data
变量和print(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)
同时,您实际想要的似乎是将第一个请求中的名称存储为每个客户机状态,这样您就可以在将来的每个请求中重用它。那几乎是一样的