You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3下Socket单行JSON通信解码异常的修复方案

问题

将应用移植至Python3环境,需采用UTF-8编码实现Socket通信:客户端连接服务器后发送一行JSON编码数据,读取服务器返回的一行JSON编码数据并持续通信。

服务器监听端口代码

def handle_oracle_query(self, sock, address):
    sockIn = sock.makefile('rb')
    sockOut = sock.makefile('wb')
    line = sockIn.readline()
    submitted_data = json.loads(line)
    self.get_thread_specific_storage()['environmental_variables'] = submitted_data['environmental_variables']
    self.get_thread_specific_storage()['cgi'] = submitted_data['cgi']
    generate_output()
    print_output(sockOut)
    sock.close()
    sockIn.close()
    sockOut.close()
    self.remove_thread_specific_storage()

客户端连接代码

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = server[0]
try:
    port = int(server[1])
except:
    port = DEFAULT_PORT
sock.connect((ip, port))
sockIn = sock.makefile("rb")
sockOut = sock.makefile("wb")
cgi_hash = {}
for key in cgi.FieldStorage().keys():
    cgi_hash[key] = cgi.FieldStorage()[key].value
as_dictionary = dict(os.environ)
submitted_data = {
  'environmental_variables': as_dictionary,
  'cgi': cgi_hash}
encoded_data = json.dumps(submitted_data)
sys.stderr.write(encoded_data + '\r\n')
sockOut.write(encoded_data + '\r\n')
sockOut.flush()
result = json.loads(sockIn.read())
sock.close()
sockIn.close()
sockOut.close()

运行异常栈

Traceback (most recent call last):
  File "/home/christos/fathers/bin/./fathersd", line 4075, in <module>
    multitasking.start_oracle()
  File "/home/christos/fathers/bin/./fathersd", line 2396, in start_oracle
    self.run_oracle()
  File "/home/christos/fathers/bin/./fathersd", line 2372, in run_oracle
    self.handle_oracle_query(newsocket, address)
  File "/home/christos/fathers/bin/./fathersd", line 2309, in handle_oracle_query
    submitted_data = json.loads(line)
  File "/usr/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
解决方案

核心问题分析

Python3中字节串(bytes)与字符串(str)严格区分,原代码未正确处理编码转换:客户端直接发送字符串拼接字节换行符,服务器读取字节串后未解码就传入json.loads,导致解析失败。

客户端修改点

  • 改用文本模式处理Socket流:创建makefile时指定UTF-8编码,自动完成字符串与字节的转换,避免手动编码错误。
  • 修正数据发送逻辑:文本模式下直接写入JSON字符串,无需手动拼接字节换行符。
  • 按行读取服务器返回:原代码sockIn.read()会读取所有数据,不符合单行JSON需求,改用readline()读取单行内容。

修改后的客户端代码:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = server[0]
try:
    port = int(server[1])
except:
    port = DEFAULT_PORT
sock.connect((ip, port))
# 文本模式+UTF-8编码,自动处理字符串/字节转换
sockIn = sock.makefile("r", encoding='utf-8')
sockOut = sock.makefile("w", encoding='utf-8')
cgi_hash = {}
for key in cgi.FieldStorage().keys():
    cgi_hash[key] = cgi.FieldStorage()[key].value
as_dictionary = dict(os.environ)
submitted_data = {
  'environmental_variables': as_dictionary,
  'cgi': cgi_hash}
encoded_data = json.dumps(submitted_data)
sys.stderr.write(f"{encoded_data}\r\n")
# 文本模式直接写字符串,自动编码为UTF-8字节
sockOut.write(f"{encoded_data}\r\n")
sockOut.flush()
# 按行读取单行JSON返回
result_line = sockIn.readline()
result = json.loads(result_line)
sock.close()
sockIn.close()
sockOut.close()

服务器修改点

  • 改用文本模式处理Socket流:同样指定UTF-8编码,直接读取字符串,避免手动解码操作。
  • 增加防御性判断:读取到空行时(客户端异常断开)直接终止流程,避免JSON解析报错。
  • 确保输出刷新:发送数据后主动刷新缓冲区,保证数据及时传输到客户端。

修改后的服务器代码:

def handle_oracle_query(self, sock, address):
    # 文本模式+UTF-8编码,直接操作字符串
    sockIn = sock.makefile('r', encoding='utf-8')
    sockOut = sock.makefile('w', encoding='utf-8')
    line = sockIn.readline()
    # 防御客户端断开导致的空行
    if not line:
        sock.close()
        return
    submitted_data = json.loads(line)
    self.get_thread_specific_storage()['environmental_variables'] = submitted_data['environmental_variables']
    self.get_thread_specific_storage()['cgi'] = submitted_data['cgi']
    generate_output()
    # print_output需输出单行JSON字符串,文本模式自动编码为UTF-8
    print_output(sockOut)
    sockOut.flush()
    sock.close()
    sockIn.close()
    sockOut.close()
    self.remove_thread_specific_storage()

额外注意事项

  • 确保generate_output和print_output函数生成单行JSON字符串,避免换行符导致客户端解析错误。
  • 可使用with语句自动管理Socket和文件对象的生命周期,避免手动关闭遗漏:
    with sock.makefile('r', encoding='utf-8') as sockIn, sock.makefile('w', encoding='utf-8') as sockOut:
        # 处理逻辑
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:42:13