【问题标题】:How can I properly receive data with a TCP Python socket until a delimiter is found?在找到分隔符之前,如何使用 TCP Python 套接字正确接收数据?
【发布时间】:2021-08-21 19:47:18
【问题描述】:

我从一个未事先指定数据长度的源 (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 期间连接断开时不会引发异常( ) 调用,它只是返回一个空字符串)。

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()

【问题讨论】:

    标签: python sockets tcp


    【解决方案1】:

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

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      • 2014-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多