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

Python Socket UDP发送JSON报WinError 10040错误求助

UDP发送JSON数据触发WinError 10040问题排查

问题描述

尝试通过UDP向另一台电脑传输JSON数据,编写了JSON_UDP类,初期可正常工作,但运行一段时间后触发系统错误:

OSError: [WinError 10040] A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself

数据包大小约128字节,发送频率约每秒20次。数据包越大,错误出现得越快,即使接收端未连接也会触发该错误。

现有代码

基础UDP发送类

import socket
import json

class JSON_UDP:
    def __init__(self,send_ip='127.0.0.1', send_port=7002):
        self.send_ip = send_ip
        self.send_port = send_port      
        self.sender = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # UDP
 
    def send(self,input,send_ip='127.0.0.1', send_port=7002):
        self.send_ip = send_ip
        self.send_port = send_port
        self.input = input
        data = json.dumps(self.input)
        data = bytes(data,encoding="utf-8")
        print(len(data))

        self.sender.sendto(data, (self.send_ip, self.send_port))

尝试的缓冲区设置代码

self.buff_size = 1024
self.sender.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,self.buff_size)
self.sender.bind(('0.0.0.0',0))

问题原因与解决方法

  • 核心错误原因:你错误设置了接收缓冲区(SO_RCVBUF),但问题根源在发送socket的接收缓冲区堆积了ICMP错误报文。当接收端不存在/不可达时,系统会返回「端口不可达」的ICMP错误,这些错误会被UDP发送socket接收并存储。当缓冲区被填满后,后续的sendto操作就会触发WinError 10040。
  • 修正方向:
    1. 无需盲目调整缓冲区大小,关键是清理堆积的ICMP错误报文。
    2. 避免不必要的绑定操作:UDP客户端默认会自动绑定随机端口,重复绑定可能引发额外问题。

修正后的示例代码

import socket
import json

class JSON_UDP:
    def __init__(self,send_ip='127.0.0.1', send_port=7002):
        self.send_ip = send_ip
        self.send_port = send_port      
        self.sender = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        # 设置非阻塞模式,用于清理ICMP错误
        self.sender.setblocking(False)

    def send(self, input_data, send_ip=None, send_port=None):
        self.send_ip = send_ip or self.send_ip
        self.send_port = send_port or self.send_port
        data = json.dumps(input_data).encode("utf-8")
        print(len(data))
        
        try:
            self.sender.sendto(data, (self.send_ip, self.send_port))
            # 循环读取并丢弃堆积的ICMP错误报文
            while True:
                try:
                    self.sender.recvfrom(1024)
                except BlockingIOError:
                    # 没有更多错误报文,退出循环
                    break
        except OSError as e:
            print(f"发送失败: {e}")

额外说明

UDP是无连接协议,发送方无法直接感知接收端状态。当接收端不可达时,系统生成的ICMP错误会占用发送socket的接收缓冲区,不及时清理就会导致后续发送操作失败。数据包越大、发送频率越高,缓冲区被填满的速度就越快,错误出现得也就越早。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:27:53