Python中正确处理TCP流并按行拆分:解决半行数据问题
解决TCP连接下HTTP行拆分不完整的问题
你的核心问题是没有严格按照HTTP的\r\n行分隔规则处理缓冲区数据,原代码依赖BytesIO的默认行迭代(按\n分割),且未正确保留不完整的行,导致慢连接下半行数据被错误传入handle_line。以下是具体解决思路:
思路1:用字节缓冲区手动拆分完整行
放弃BytesIO,改用一个字节变量存储未处理的剩余数据,每次接收新数据后按\r\n拆分,只处理完整的行,不完整的留到下一轮:
def listener(client, address): try: remaining_data = b'' # 存储未处理的半行数据 while True: resp = client.recv(1024) if not resp: logging.info('Connection closed by ' + str(address)) break remaining_data += resp # 按\r\n拆分,最后一个元素是不完整的行(或空字符串) lines = remaining_data.split(b'\r\n') # 留存不完整的行到下一次处理 remaining_data = lines[-1] # 遍历处理所有完整行 for line in lines[:-1]: if line: # 跳过HTTP头结束时的空行 handle_line(client, line + b'\r\n') # 还原行尾分隔符,可根据handle_line需求调整 except IOError as e: if e.errno == errno.EPIPE: logging.warning(e) else: logging.warning(e) finally: client.close()
思路2:用BytesIO配合指定分隔符的readline
如果坚持用BytesIO,可以用readline指定\r\n作为分隔符,仅读取完整的行:
def listener(client, address): try: with BytesIO() as buffer: while True: resp = client.recv(1024) if not resp: logging.info('Connection closed by ' + str(address)) break buffer.write(resp) buffer.seek(0) # 循环读取所有完整的\r\n结尾行 while True: line = buffer.readline(b'\r\n') if not line: # 没有完整行,退出循环 break handle_line(client, line) # readline会保留末尾的\r\n # 留存剩余的半行数据 remaining = buffer.read() buffer.truncate(0) buffer.write(remaining) except IOError as e: if e.errno == errno.EPIPE: logging.warning(e) else: logging.warning(e) finally: client.close()
关键注意点
- 必须严格以
\r\n作为行分隔符,不能依赖默认的\n分割,否则会误判不完整的行 - 无论哪种方案,都要确保只有包含完整
\r\n的行才会传给handle_line,不完整的部分必须留到下一次接收新数据后再处理 - 原代码中的
time.sleep(0.5)完全无效,慢连接下数据是分批到达的,休眠无法保证收到完整行,必须通过缓冲区拼接+分隔符判断来处理
内容的提问来源于stack exchange,提问作者Piotr K
相关产品推荐
相关产品推荐

