You need to enable JavaScript to run this app. Socket通信重复读取同一行,如何实现单行读取后等待下一次输入
优惠活动
大模型
产品
解决方案
定价
更多

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

调整后运行流程完全匹配预期:

  1. 服务端启动后先等待用户在控制台输入指令,不会提前缓存固定数据
  2. 客户端发起连接时,服务端把用户输入的带换行标记的内容发给客户端
  3. 客户端收到内容后正常解析出完整一行,打印输出后,因为服务端发完就关连接,客户端读到空值会自动停止读取,不会重复刷屏
  4. 服务端关闭连接后,回到控制台等待用户输入下一次要发送的指令,进入下一轮循环

内容的提问来源于stack exchange,提问作者brad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 21:06:03