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

Python UDP客户端单次创建套接字收发数据报错咨询

UDP单套接字收发问题说明

我在编写支持同时收发数据的UDP客户端时,目前只能通过每次收发时重复创建、关闭套接字实现功能,该实现方式不合理,理想状态应该是进入循环前创建一次套接字,循环退出后再统一关闭。
测试过程中发现:注释接收相关代码时,仅在for循环前创建一次套接字、循环结束后关闭,发送功能可正常运行;恢复接收代码后,根据接收代码放置位置不同,程序要么卡在s.recvfrom()调用处,要么卡在s.bind()调用处。

可正常运行的重复创建套接字版本代码

import socket
import time
import struct

TX_UDP_IP = '172.24.15.34' #IP address of ETH SFP
TX_UDP_PORT = 4575

#TX Packet Header
TX_PACKETVERSION = 1
TX_P8ADDRESSOFFSET = 0
TX_SEQUENCENUM = 0

RX_UDP_IP = '172.24.2.7' #IP address of local machine
RX_UDP_PORT = 4575

BUFFER_SIZE = 1024

print("Entered Loop")
start = time.perf_counter()
for i_python in range(1,11):
    
    f_python = float(i_python) + 0.15

  
    send_data_str = struct.pack('>iiiid', TX_PACKETVERSION, TX_P8ADDRESSOFFSET, TX_SEQUENCENUM, i_python, f_python)
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.sendto(send_data_str, (TX_UDP_IP, TX_UDP_PORT))
    s.close()

    
    TX_SEQUENCENUM = TX_SEQUENCENUM + 1
    if TX_SEQUENCENUM > 1000:
        TX_SEQUENCENUM = 0
    
    print("Transmitted i_python = ",i_python," and f_python = ",f_python)
    
    time.sleep(1.0)
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind((RX_UDP_IP, RX_UDP_PORT))
    recv_data_str = s.recvfrom(BUFFER_SIZE)
    s.close()
    
    recv_data_str_unpacked = struct.unpack(">iiiid",recv_data_str[0])
    RX_PACKETVERSION = recv_data_str_unpacked[0]
    RX_P8ADDRESSOFFSET = recv_data_str_unpacked[1]
    RX_SEQUENCENUM = recv_data_str_unpacked[2]
    j_RTDS = recv_data_str_unpacked[3]
    t_RTDS = recv_data_str_unpacked[4]
    
    print("Recieved j_RTDS = ",j_RTDS," and t_RTDS = ",t_RTDS)
    
    
print ("Exited Loop")
finish = time.perf_counter() - start
print ('The execution time is %fs.' %finish)

2021-07-26补充内容

报错版本代码

import socket
import time
import struct

TX_UDP_IP = '172.24.15.34' #IP address of ETH SFP
TX_UDP_PORT = 4575

#TX Packet Header
TX_PACKETVERSION = 1
TX_P8ADDRESSOFFSET = 0
TX_SEQUENCENUM = 0

RX_UDP_IP = '172.24.2.7' #IP address of local machine
RX_UDP_PORT = 4575

BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)


print("Entered Loop")
start = time.perf_counter()
for i_python in range(1,11):
    
    f_python = float(i_python) + 0.15

  
    send_data_str = struct.pack('>iiiid', TX_PACKETVERSION, TX_P8ADDRESSOFFSET, TX_SEQUENCENUM, i_python, f_python)
    s.sendto(send_data_str, (TX_UDP_IP, TX_UDP_PORT))

    
    TX_SEQUENCENUM = TX_SEQUENCENUM + 1
    if TX_SEQUENCENUM > 1000:
        TX_SEQUENCENUM = 0
    
    print("Transmitted i_python = ",i_python," and f_python = ",f_python)
    
    time.sleep(1.0)
    
    s.bind((RX_UDP_IP, RX_UDP_PORT))
    recv_data_str = s.recvfrom(BUFFER_SIZE)
    
    recv_data_str_unpacked = struct.unpack(">iiiid",recv_data_str[0])
    RX_PACKETVERSION = recv_data_str_unpacked[0]
    RX_P8ADDRESSOFFSET = recv_data_str_unpacked[1]
    RX_SEQUENCENUM = recv_data_str_unpacked[2]
    j_RTDS = recv_data_str_unpacked[3]
    t_RTDS = recv_data_str_unpacked[4]
    
    print("Recieved j_RTDS = ",j_RTDS," and t_RTDS = ",t_RTDS)
    
    
print ("Exited Loop")
s.close()
finish = time.perf_counter() - start
print ('The execution time is %fs.' %finish)

报错信息

Exception has occurred: OSError
[WinError 10022] An invalid argument was supplied
  File "C:\UDP_SKT_Python_R06.py", line 51, in <module>
    s.bind((RX_UDP_IP, RX_UDP_PORT))
问题原因与解决方法

错误原因

  1. 套接字的bind()操作仅允许执行一次,你将s.bind()放在for循环内部,第一次循环绑定完成后,第二次循环重复调用就会触发无效参数错误。
  2. 绑定完成的UDP套接字同时支持发送和接收操作,不需要为收发分别创建套接字。
  3. 默认s.recvfrom()为阻塞调用,如果对端没有返回数据会一直卡住,可根据需求设置超时时间避免永久阻塞。

修正后的代码

import socket
import time
import struct

TX_UDP_IP = '172.24.15.34' # ETH SFP的IP地址
TX_UDP_PORT = 4575

# 发送数据包头部
TX_PACKETVERSION = 1
TX_P8ADDRESSOFFSET = 0
TX_SEQUENCENUM = 0

RX_UDP_IP = '172.24.2.7' # 本地机器的IP地址
RX_UDP_PORT = 4575

BUFFER_SIZE = 1024

# 创建套接字后直接绑定,仅执行一次
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((RX_UDP_IP, RX_UDP_PORT))
# 可选配置:设置接收超时,单位为秒,超时后会抛出socket.timeout异常
s.settimeout(5.0)

print("进入循环")
start = time.perf_counter()
for i_python in range(1,11):
    f_python = float(i_python) + 0.15
    send_data_str = struct.pack('>iiiid', TX_PACKETVERSION, TX_P8ADDRESSOFFSET, TX_SEQUENCENUM, i_python, f_python)
    # 直接用已绑定的套接字发送数据
    s.sendto(send_data_str, (TX_UDP_IP, TX_UDP_PORT))
    
    TX_SEQUENCENUM = TX_SEQUENCENUM + 1
    if TX_SEQUENCENUM > 1000:
        TX_SEQUENCENUM = 0
    
    print("已发送i_python = ",i_python," ,f_python = ",f_python)
    
    time.sleep(1.0)
    
    # 直接用同一个套接字接收数据,不需要重复绑定
    try:
        recv_data_str = s.recvfrom(BUFFER_SIZE)
    except socket.timeout:
        print("接收超时,跳过本次接收")
        continue
    
    recv_data_str_unpacked = struct.unpack(">iiiid",recv_data_str[0])
    RX_PACKETVERSION = recv_data_str_unpacked[0]
    RX_P8ADDRESSOFFSET = recv_data_str_unpacked[1]
    RX_SEQUENCENUM = recv_data_str_unpacked[2]
    j_RTDS = recv_data_str_unpacked[3]
    t_RTDS = recv_data_str_unpacked[4]
    
    print("已接收j_RTDS = ",j_RTDS," ,t_RTDS = ",t_RTDS)
    
print("退出循环")
s.close()
finish = time.perf_counter() - start
print ('执行耗时为 %fs.' %finish)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 09:12:03