我正在将SocketServer模块用于TCP服务器。我在此recv()函数遇到一些问题,因为传入的数据包总是具有不同的大小,所以如果我指定recv(1024)(我尝试使用更大的值,并且更小),则它在2或3个请求后卡住,因为数据包长度会变小(我认为),然后服务器卡住直到超时。
recv()
recv(1024)
class Test(SocketServer.BaseRequestHandler): def handle(self): print "From:", self.client_address while True: data = self.request.recv(1024) if not data: break if data[4] == "\x20": self.request.sendall("hello") if data[4] == "\x21": self.request.sendall("bye") else: print "unknow packet" self.request.close() print "Disconnected", self.client_address launch = SocketServer.ThreadingTCPServer(('', int(sys.argv[1])),Test) launch.allow_reuse_address= True; launch.serve_forever()
如果客户端通过同一源端口发送多个请求,但服务器卡住,则非常感谢您的帮助,谢谢!
网络 总是 不可预测的。TCP使许多这种随机行为为您消除。TCP要做的一件奇妙的事情:它确保字节将以相同的顺序到达。但!它 不能 保证它们会以相同的方式切碎。您根本 无法 假设连接一端的每个send()都会导致远端上的一个recv()的字节数完全相同。
当您说时socket.recv(x),您的意思是“直到您从套接字读取了x个字节后,才返回”。这称为“阻止I / O”:您将阻止(等待)直到您的请求得到满足。如果协议中的每条消息都恰好是1024字节,则调用socket.recv(1024)将非常有用。但这听起来不对。如果您的消息是固定的字节数,只需将该数字传递给socket.recv()您就可以了。
socket.recv(x)
socket.recv(1024)
socket.recv()
但是,如果您的邮件可以具有不同的长度怎么办?您需要做的第一件事:停止socket.recv()使用明确的电话号码。改变这个:
data = self.request.recv(1024)
对此:
data = self.request.recv()
recv()只要获得新数据,均值将始终返回。
但是现在您遇到了一个新问题:您怎么知道发件人何时向您发送了完整的消息?答案是:您不知道。您将必须使消息的长度成为协议的明确部分。最好的方法是:为每个消息加一个前缀,长度可以是固定大小的整数(使用socket.ntohs()或socket.ntohl()Please转换为网络字节顺序),也可以是字符串后跟一些定界符(例如‘123:’)。第二种方法通常效率较低,但在Python中更容易。
socket.ntohs()
socket.ntohl()
Once you’ve added that to your protocol, you need to change your code to handle recv() returning arbitrary amounts of data at any time. Here’s an example of how to do this. I tried writing it as pseudo-code, or with comments to tell you what to do, but it wasn’t very clear. So I’ve written it explicitly using the length prefix as a string of digits terminated by a colon. Here you go:
length = None buffer = "" while True: data += self.request.recv() if not data: break buffer += data while True: if length is None: if ':' not in buffer: break # remove the length bytes from the front of buffer # leave any remaining bytes in the buffer! length_str, ignored, buffer = buffer.partition(':') length = int(length_str) if len(buffer) < length: break # split off the full message from the remaining bytes # leave any remaining bytes in the buffer! message = buffer[:length] buffer = buffer[length:] length = None # PROCESS MESSAGE HERE