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

Python Socket编程中JSON发送字节时服务器JSON解码报错问题

问题:Socket传输JSON时服务端解析失败

我编写了一个Socket程序,需求如下:选择文件,读取文件内容,将读取的文件转换为字节列表,每次将列表中的一个元素以JSON格式单独发送到服务器,在服务器端加载JSON并打印。目前文件读取、字节列表转换、JSON格式发送均正常,但服务器端解析JSON时出现如下错误:

{'type': 'fileUpload', 'file': 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAA7EAAAOxAGVKw4bAAATPElEQVR42s1be2xT1R//3Hv7Wtm6dXNjZWxswgabDsabgThIjAMVBKe44BOjRjBEUYnySAQfBBPBVwJBxWCMiqIoBAQHSoLKBBcCDDYeY2wdm92rXdv1dV/f3x+kl7a7bccYv/hNbnp7envu+Z7zPd/v53zO9zB0TQAADMMgeB/8DgChvwe/q92HSrTy0N8i6+np6QHDMOjo6IAkSRg9ejRYlgURQRAE/PPPPxg5ciQyMzP7VX+0d4XpFNS+u7sbAJCWlgYigtfrxZAhQ/r8IbSj1CqO1qDITlVrsCzLAABZlkFE0Gq1yjOSJKGzsxPJyckwGAzqykRRNFZ7NcGHAoEAJElCWlqa8kI15dQqH4hIkgRJkiDLMliWhU6nA8uyUS2N4zhl5COVjmxD6P/UPsN+p9DhiaJYNJONvJckCe3t7ZBlGSaTCQaDARzHQZZldHd3w+12w2q1orq6Gr29vfB4PHC73TCZTHj44YcxdepUsCwLnueRkJCgmP/NTLdY7QcARpZl6q9Jhz6jZg29vb147rnncPjwYZjNZlgsFuTk5MDhcODkyZNwOp0IBAKKqYeKwWDAQw89hKFDh6KmpgZlZWV48sknMWrUqD7vVBmzfvuryGmsiTSRWBKtg2RZhtVqRV1dHXieR3d3N7q7u9HY2IiamhqwLIsFCxZAlmV89913qnX7/X58++23yqg7HA40NTVh+PDhKC8vx6hRo5Camgqj0RjVCgKBAHQ6HQRBgF6vj9pJoR2jiWc28aZGU1MTvvrqK9TV1cFsNkMQBBgMBoiiiFmzZiE/Px88zyMjIwP//POP6ujpdDoYDAbk5eXh6tWrcLlcEAQBL774Ik6ePInXX38dDMNg69atKCkpUVWEYRhoNBowDAOO42JGqzA/Qv0QWZb7lEmSRDU1NTR79myaMmUKVVVV0Z49e+iJJ56glJQUAkAcxxHHcQQg7GIYRrlnWZays7NJr9fTkiVLqKSkhMaMGUNFRUW0cuVKmjZtGqWkpBDDMPTII4/QqVOniOf5G2qzWvuDguCPkX8IXoFAgCKfkWWZqquracGCBfTll1+S1+ul48eP04QJEwgAaTSaPkoDoJycHCorK6MHHniAWJYlAGSxWOi+++6j4uJiWrRoERUWFtI777xDSUlJlJ2dTUOHDqXExESljvT0dNqxY4dqeyPv1Tol8jlWzQeEmorH41Gdr7t37wbP87jnnntw9OhRrFq1CmfPngUAiKKoGqK0Wi1mzJiBuXPnwmQyISsrC2VlZejq6sKiRYtQWVmJlA=='}
Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Users\PC\AppData\Local\Programs\Python\Python39\lib\threading.py", line 980, in _bootstrap_inner
    self.run()
  File "C:\Users\PC\AppData\Local\Programs\Python\Python39\lib\threading.py", line 917, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\PC\Desktop\New folder (5)\server.py", line 11, in listen_for_messages
    message = json.loads(message)
  File "C:\Users\PC\AppData\Local\Programs\Python\Python39\lib\json\__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "C:\Users\PC\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 340, in decode
    raise JSONDecodeError("Extra data", s, end)
json.decoder.JSONDecodeError: Extra data: line 1 column 1403 (char 1402)

客户端代码(client.py)

from PyQt6.QtWidgets import *
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import socket
import threading
import json
import os
import base64


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.show()

        self.fileBtn = QPushButton('file upload')
        self.fileBtn.clicked.connect(self.fileUpload)
        mainWidget = QWidget()
        layout = QVBoxLayout()
        mainWidget.setLayout(layout)
        layout.addWidget(self.fileBtn)
        self.setCentralWidget(mainWidget)

        self.connect()

    def connect(self):
        self.HOST = '127.0.0.1'
        self.PORT = 1234
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client.connect((self.HOST, self.PORT))

    def fileUpload(self):
        fileName, ok = QFileDialog.getOpenFileName(self)
        if ok:
            file = open(fileName , 'rb')
            file = file.read()
            _range = 1024
            def reader(data):
                for i in range(0, len(data), _range):
                    yield data[i:i+_range]
            lst = list(reader(file))

            for elem in lst:
                dic = json.dumps({
                    "type":"fileUpload",
                    "file":base64.b64encode(elem).decode('utf-8'),
                })
                self.client.sendall(bytes(dic,encoding="utf-8"))      

app = QApplication([])
win = Window()
app.exec()

服务端代码(server.py)

import socket
import threading
import json
LISTENER_LIMIT = 5
HOST = '127.0.0.1'
PORT = 1234

def listen_for_messages(client):
    while True:
        message = client.recv(2048).decode('utf-8')
        message = json.loads(message)
        print(message)

def main():

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        server.bind((HOST, PORT))
    except:
        print(f"Unable to bind to host {HOST} and port {PORT}")
    server.listen(LISTENER_LIMIT)
    while 1:
        client,address = server.accept()
        threading.Thread(target=listen_for_messages, args=(client, )).start()

if __name__ == '__main__':
    main()

问题原因及解决方案

问题根源

TCP是流式协议,没有数据包边界。recv(2048)可能一次接收到多个客户端发送的JSON数据包,或者一个完整的JSON被拆分成多次接收。而json.loads()只能解析单个JSON对象,当输入是多个JSON拼接的字符串时,就会抛出"Extra data"错误。

解决方案:添加数据包分隔符

最简单可靠的方法是给每个JSON数据包末尾添加**换行符\n**作为分隔符,服务端接收数据后按分隔符拆分,确保每次只解析一个完整的JSON。

1. 修改客户端发送逻辑

在生成的JSON字符串后添加换行符再发送:

# 原代码
# self.client.sendall(bytes(dic,encoding="utf-8"))
# 修改后
self.client.sendall(bytes(dic + '\n', encoding="utf-8"))

2. 修改服务端接收逻辑

维护一个缓冲区,将每次接收的片段拼接起来,按换行符拆分出完整的JSON进行解析:

def listen_for_messages(client):
    buffer = ""
    while True:
        chunk = client.recv(2048).decode('utf-8')
        if not chunk:
            break  # 客户端断开连接
        buffer += chunk
        # 循环处理所有完整的JSON数据包
        while '\n' in buffer:
            # 拆分出第一个完整的JSON,剩下的留在缓冲区
            message, buffer = buffer.split('\n', 1)
            if message.strip():  # 跳过空内容
                try:
                    data = json.loads(message)
                    print(data)
                except json.JSONDecodeError as e:
                    print(f"解析JSON错误: {e}")

替代方案:发送数据包长度

更严谨的方式是先发送JSON数据包的字节长度(比如用固定4字节的整数),服务端先接收长度,再接收对应长度的字节进行解析。这种方式适合对可靠性要求极高的场景,但代码复杂度稍高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 12:37:33