Socket通信重复读取同一行,如何实现单行读取后等待下一次输入
问题根源定位
- 程序反复刷相同内容的最核心原因:客户端存在逻辑完全失效的嵌套循环。第一次拿到有效内容进入内层
while(line)块之后,代码全程没有重新给line赋值的操作,只要line不是空值,就会永远卡死在这层循环里反复打印同一个字符串,根本不会走到外层的重新读行逻辑。 - 通信协议不对齐:你自定义的
LineReader类是依靠b'\n'作为行分割边界的,但服务端发送的数据是用户输入的原始内容,没有附带换行符,导致客户端的LineReader永远找不到行结束标记,直到服务端关闭连接时,才把整个缓冲区的内容作为一整行返回,直接触发上述的无限循环bug。 - 服务端逻辑不符合预期:你现在的服务端只在程序启动时读取一次控制台输入的命令,之后所有新连接都会反复发送这份固定不变的
test_data,根本不会在流程中等待用户输入新指令,哪怕修正了客户端的循环bug,也达不到“读完一行就暂停、等待下一次数据输入”的效果。
调整方案
- 移除客户端多余的内层死循环:每读取到一行内容、完成打印和处理后,直接判断是否需要继续读取,不要在没有刷新变量值的情况下做无意义循环。
- 统一两端的行分隔约定:服务端在发送的内容末尾追加
\n换行符,让客户端的LineReader能正常识别一行的结束,实现“读到一行就返回、不攒多余数据”的效果。 - 把服务端的用户输入逻辑移到连接处理循环内:每次完成一次数据发送、关闭连接后,再回到控制台等待新的用户输入,不要启动时只读一次永久复用。
- 增加空值判断:当客户端读到LineReader返回的空字符串时,说明服务端已经完全关闭连接,直接退出读循环即可。
修正后服务端代码
import socket import time s = socket.socket() s.bind(('localhost', 666)) s.listen() print("服务端已启动,等待输入指令...") while True: # 每次发完上一轮数据,再等待新的用户输入 inputdata = input("Enter command: ") # 追加换行符对齐客户端的行分割逻辑 test_data = bytes(inputdata + '\n', encoding='utf-8') c, addr = s.accept() print(f"收到来自 {addr} 的连接") try: # 用sendall保证所有数据完整发送,避免send的分片遗漏 c.sendall(test_data) except Exception as e: print(e) finally: time.sleep(0.1) c.shutdown(socket.SHUT_RDWR) c.close() print("本次数据发送完成,等待下一次指令输入")
修正后客户端代码
import socket import sys readOut = 0 ipaddr = 'localhost' ipport = 666 print ("Starting up") class LineReader: def __init__(self, socket, encoding='ascii'): self.s = socket self.encoding = encoding self.buf = b'' self.closed = False def readline(self): while True: index = self.buf.find(b'\n') if index >= 0: line = self.buf[:index+1] self.buf = self.buf[index+1:] # 去掉返回值里的换行符,方便后续业务判断 return line.decode(self.encoding).rstrip('\n') if self.closed: line = self.buf self.buf = b'' # 连接关闭且缓冲区无残留数据时,返回空字符串触发退出逻辑 return line.decode(self.encoding) if line else '' data = self.s.recv(1024) self.closed = len(data) == 0 print("raw recv:", data) self.buf += data with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: s.connect((ipaddr , ipport)) reader = LineReader(s) while True: line = reader.readline() # 删掉原来错误的内层while(line)死循环 if not line: break print(f"Reading: {line}") if "Fahrenheit" in line: cread = line[22:-2] newcread = float(cread) print("cread ", cread, "newcread ", newcread) finally: print('closing socket', file=sys.stderr) s.close()
调整后运行流程完全匹配预期:
- 服务端启动后先等待用户在控制台输入指令,不会提前缓存固定数据
- 客户端发起连接时,服务端把用户输入的带换行标记的内容发给客户端
- 客户端收到内容后正常解析出完整一行,打印输出后,因为服务端发完就关连接,客户端读到空值会自动停止读取,不会重复刷屏
- 服务端关闭连接后,回到控制台等待用户输入下一次要发送的指令,进入下一轮循环
内容的提问来源于stack exchange,提问作者brad
相关产品推荐
相关产品推荐

