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

Python Socket传输MySQL导出字符串时丢失末尾字符故障排查问询

问题原因与修复方案

根因分析

故障核心是混淆了UTF-8字符串的字符长度与编码后的字节长度:

  • 普通ASCII字符的UTF-8编码长度与字符长度一致,所以常规消息传输正常
  • MySQL导出的字符串包含Ł这类非ASCII拉丁扩展字符,单个字符UTF-8编码占2字节,你客户端代码中len(msg_to_send)计算的是字符个数,远小于实际编码后的字节总长度
  • 你将错误的长度值放在消息头传给服务端,服务端按偏小的长度收消息,就会少收末尾的几个字节,末尾的]就会留在缓冲区,被下一次读取消息头的操作拿到,就出现了]6无法转整数的报错。

另外原代码还存在socket半包问题:send不保证一次性发送完所有字节,recv也不保证一次性读满指定长度的字节,就算长度计算正确,传输大内容时也可能出现异常。

修复代码

客户端修改

import socket
import time

PORT = 9696
FORMAT = 'utf-8'
SERVER = "localhost"
ADDR = (SERVER, PORT)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)

def send(msg):
    msg_bytes = msg.encode(FORMAT)
    # 计算编码后的字节长度作为头部值
    msg_len = len(msg_bytes)
    header = str(msg_len) + ("#" * (30 - len(str(msg_len))))
    header_bytes = header.encode(FORMAT)
    # 循环发送保证头部全部发出
    sent = 0
    while sent < len(header_bytes):
        sent += client.send(header_bytes[sent:])
    # 循环发送保证消息内容全部发出
    sent = 0
    while sent < len(msg_bytes):
        sent += client.send(msg_bytes[sent:])

# 替换为你的MySQL导出字符串
msg_to_send = "[('index', 'bigint(20)', 'YES', 'MUL', None, ''), ('LP', 'text', 'YES', '', None, ''), (' NR-a', 'text', 'YES', '', None, ''), ('LITERA-a', 'text', 'YES', '', None, ''), ('MUFA-a', 'double', 'YES', '', None, ''), ('UWAGI-a', 'text', 'YES', '', None, ''), ('TUBY-a', 'double', 'YES', '', None, ''), ('DATA1-a', 'text', 'YES', '', None, ''), ('DATA2-a', 'text', 'YES', '', None, ''), ('SPAWY-i', 'text', 'YES', '', None, ''), ('SPAWY_DAC-i', 'text', 'YES', '', None, ''), ('LOG-a', 'text', 'YES', '', None, ''), ('SPLIT1X4-i', 'text', 'YES', '', None, ''), ('SPLIT1X8-i', 'text', 'YES', '', None, ''), ('SPLIT1X16-i', 'text', 'YES', '', None, ''), ('ADAPTERY SIMPLE-i', 'double', 'YES', '', None, ''), ('ADAPTERY DUPLEX-i', 'double', 'YES', '', None, ''), ('PIGTAIL-i', 'double', 'YES', '', None, ''), ('OLT-a', 'double', 'YES', '', None, ''), ('NEXT-a', 'double', 'YES', '', None, ''), ('ODNOGA_1-a', 'double', 'YES', '', None, ''), ('ODNOGA_2-a', 'double', 'YES', '', None, ''), ('ODNOGA_3-a', 'double', 'YES', '', None, ''), ('ODNOGA_4-a', 'double', 'YES', '', None, ''), ('DROP30-i', 'double', 'YES', '', None, ''), ('DROP50-i', 'double', 'YES', '', None, ''), ('DROP70-i', 'double', 'YES', '', None, ''), ('DROP80-i', 'double', 'YES', '', None, ''), ('DROP100-i', 'double', 'YES', '', None, ''), ('DROP120-i', 'double', 'YES', '', None, ''), ('DROP150-i', 'double', 'YES', '', None, ''), ('DROP200-i', 'double', 'YES', '', None, ''), ('MAŁPKI-i', 'double', 'YES', '', None, '')]"

time.sleep(3)
for i in range(1000):
    send(msg_to_send)

while True:
    pass

服务端修改

import socket
import threading

PORT = 9696
SERVER = "localhost"
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'

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

# 新增工具函数:保证收满指定长度的字节
def recv_exact(conn, length):
    data = b''
    while len(data) < length:
        chunk = conn.recv(length - len(data))
        if not chunk:
            raise RuntimeError("连接已断开")
        data += chunk
    return data

def handle_client(conn):
    while True:
        # 先收满30字节的头部
        header = recv_exact(conn, 30).decode(FORMAT)
        actual_size = int(header.replace("#", ""))
        # 再收满对应长度的消息内容
        msg_bytes = recv_exact(conn, actual_size)
        received_message = msg_bytes.decode(FORMAT)
        print(len(received_message))
        # 验证末尾字符
        print(received_message[-1])

def start():
    server.listen()
    while True:
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn,))
        thread.start()

start()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:09:00