在找到分隔符之前,如何使用 TCP Python 套接字正确接收数据?

How can I properly receive data with a TCP Python socket until a delimiter is found?

我从一个没有预先指定数据长度的源 (Twitch IRC) 接收数据,并且它从不发送一致数量的数据。此源使用“\r\n”作为其分隔符,我想接收数据直到找到此分隔符,停止接收以处理接收到的数据,然后继续接收。我已经尝试了一些我想出的解决方案:

delimiter = "\r\n"
buffer = ""

while True:
    received = socket.recv(1).decode("utf-8", "ignore")
    buffer += received

    if buffer.endswith(delimiter):
        process_data(buffer)
        buffer = ""

这个解决方案并不理想,因为“received”在只接收一个字节时通常是一个空字符串,这会在我的应用程序中触发一个错误处理程序(因为 Python 在连接时不会引发异常在 recv() 调用期间下降,它只是 returns 一个空字符串)。

delimiter = "\r\n"
buffer = ""

while True:
    received = socket.recv(2048).decode("utf-8", "ignore")
    received_messages = received.split(delimiter)

    for i in received_messages[:-1]:
        process_data(data)

这不是一个好的解决方案,因为 split() 删除了分隔符,这导致我无法知道列表中的最后一个元素是否是完整的消息。

在 Python TCP 套接字中找到定界符之前接收数据的最佳方式是什么?我正在寻找的功能类似于 Boost 的 boost::asio::read_until().

您可以缓冲数据并在找到分隔符后提取整个消息。示例:

server.py

from socket import *

class Buffer:

    def __init__(self,sock):
        self.sock = sock
        self.buffer = b''

    def get_line(self):
        while b'\r\n' not in self.buffer:
            data = self.sock.recv(1024)
            if not data: # socket closed
                return None
            self.buffer += data
        line,sep,self.buffer = self.buffer.partition(b'\r\n')
        return line.decode()

s = socket()
s.bind(('',5000))
s.listen()
while True:
    c,a = s.accept()
    with c:
        print('Connected:',a)
        b = Buffer(c)
        while True:
            line = b.get_line()
            if line is None:
                break
            print('line:',line)
    print('Disconnected:',a)

client.py

from socket import *

s = socket()
s.connect(('localhost',5000))
s.sendall(b'a partial')
s.sendall(b' line\r\nand another')
s.sendall(b' line\r\n')
s.close()

输出:

Connected: ('127.0.0.1', 59552)
line: a partial line
line: and another line
Disconnected: ('127.0.0.1', 59552)