找出消息中发送/接收的特定字节数。(蟒蛇)

B.K*_*.K. 2 python sockets packets

这是一个简单的python 3.x TCP服务器:

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        print(str(self.client_address[0]) + " wrote: " + str(self.data.decode()))

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()
Run Code Online (Sandbox Code Playgroud)

和客户:

import socket
import sys

HOST, PORT = "localhost", 9999

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))

while( True ):
    data = input("Msg: ")

    if data == "exit()":
        print("Exiting...")
        sock.close()
        exit();

    sock.sendall(bytes(data, "utf-8"))

#numBytes = ....?
#print("Sent: " + str( numBytes ) + " bytes\n")
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何查看消息中发送的确切字节数。我可以使用len(data),但它不能说明空终止符,因此...。是否也要发送空终止符,还是无关紧要?我尝试研究已发送/已接收消息的确切字节数,但是我找不到任何特定于python的文档,只看到了使用len()的人的示例,我认为这不是确切的...

有任何想法吗?

aba*_*ert 5

Python字符串中没有空终止符。如果您想发送一个,则必须明确地执行:sock.sendall(bytes(data, "utf-8") + b'\0')

但是,没有充分的理由首先添加一个空终止符,除非您打算将其用作消息之间​​的分隔符。(请注意,这对于一般的Python字符串不起作用,因为允许它们在中间包括空字节…,但是对于真正的人类可读文本当然也可以使用。)

使用空字节作为分隔符不是一个坏主意……但是您现有的代码需要实际处理。您不能只是打电话recv(1024)并假设这是一条完整的消息;您必须继续recv(1024)在循环中调用并追加到缓冲区,直到找到空值为止,然后保存该空值之后的所有内容,以备下次在循环中使用。


无论如何,该sendall方法不会返回发送的字节数,因为它总是准确地发送您给它的字节(除非出现错误,在这种情况下会引发错误)。所以:

buf = bytes(data, "utf-8") + b'\0'
sock.sendall(buf)
bytes_sent = len(buf)
Run Code Online (Sandbox Code Playgroud)

在服务器端,您可能想要编写一个NullTerminatedHandler类,如下所示:

class NullTerminatedHandler(socketserver.BaseRequestHandler):
    def __init__(self):
        self.buf = b''
    def handle(self):
        self.buf += self.request.recv(1024)
        messages = self.buf.split(b'\0')
        for message in messages[:-1]:
            self.handle_message(message)
        self.buf = self.buf[:-1]
Run Code Online (Sandbox Code Playgroud)

然后,您可以像这样使用它:

class MyTCPHandler(NullTerminatedHandler):
    def handle_message(self, message):
        print(str(self.client_address[0]) + " wrote: " + str(message.decode()))
Run Code Online (Sandbox Code Playgroud)

在此过程中,您遇到了一些Unicode /字符串问题。从最严重到最严重:

  • 您几乎永远不应该不decode带任何参数地打电话。如果要在一侧发送UTF-8数据,请始终在另一侧显式发送decode('utf-8')
  • decode方法保证返回a str,因此编写str(message.decode())只会使您的代码混乱。
  • 有一个原因是示例代码使用了format而不是调用str一堆对象并将它们连接在一起的原因-通常更容易阅读。
  • 通常说起来data.encode('utf-8')比更具可读性bytes(data, 'utf-8')