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

UDP接收异常:Socat/NetCat/Python收不到包但Wireshark可捕获

UDP数据包捕获异常排查问题

环境与异常情况

  • 设备A(Windows系统)运行Python网卡状态检测脚本,向设备B(Ubuntu 20.04系统)发送UDP数据
  • 5台硬件配置完全一致的测试机器中,4台运行正常,仅1台出现异常:
    • Wireshark可正常捕获UDP数据包,但nc -lup <port>、socat - udp-l:<port>,reuseaddr,fork及Python监听脚本均无法接收数据包

已做排查操作

  • 关闭ufw防火墙
  • 设置网卡广播地址为192.168.255.255
  • 问题仍未解决

相关脚本代码

tsend.py(Windows端发送脚本)

import socket, psutil
from time import sleep 

def getst(nic):
    stat = psutil.net_if_stats()
    # print(stat[nic].isup)
    if stat[nic].isup == True:
        return 'Up and ok\n'
    else:
        return 'Down, bad\n'

def main():
    UDP_IP = "192.168.100.10"
    UDP_PORT = 2275
    count = 0
    exstate = "bababooey"
    state = bytes(getst('Ethernet'), 'utf-8')
    while True:
        count += 1
        exstate = state
        state = bytes(getst('Ethernet'), 'utf-8')
        if (exstate != state) or (count >= 3): 
            count = 0
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            sock.bind(("192.168.100.20", 0))
            # print(state)
            sock.sendto(state, (UDP_IP, UDP_PORT))
            sleep(1)
            sock.sendto(state, (UDP_IP, UDP_PORT))
            sleep(1)
            sock.sendto(state, (UDP_IP, UDP_PORT))
            sock.close()
        sleep(10) 
main() 

trecv.py(Ubuntu端接收脚本)

from http.server import BaseHTTPRequestHandler, HTTPServer
import argparse
import cgi
import socket
import json
import threading
import requests
import re
import time
from datetime import datetime
import sys
from urllib import parse
import signal
    
###########----全局变量----###########

ServerIP = "1.1.1.1"
ServerPort = 1234
ServerThread = ""

##########----/全局变量----###########

class HTTPRequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        if re.search('/api/set/*', self.path):
            ctype, pdict = cgi.parse_header(self.headers.get('content-type'))
            if ctype == 'application/json':
                length = int(self.headers.get('content-length'))
                rfile_str = self.rfile.read(length).decode('utf8')
                data = parse.parse_qs(rfile_str, keep_blank_values=1)
                record_id = self.path.split('/')[-1]
                LocalData.records[record_id] = data
                log(f"Server: setstatus {record_id}: {data} " + datetime.now().strftime("%d/%m/%Y %H:%M:%S.%f")[:-3])
                # HTTP 200: 请求成功
                self.send_response(200)
            else:
                # HTTP 400: 错误请求
                log("Server: empty POST; ERR400" + datetime.now().strftime("%d/%m/%Y %H:%M:%S.%f")[:-3])
                self.send_response(400, "Bad Request: must give data")
        else:
            # HTTP 403: 禁止访问
            self.send_response(403)

        self.end_headers()

    def do_GET(self):
        if re.search('/api/shutdown', self.path):
            # 必须在另一个线程中关闭,否则会阻塞
            def kill_me_please():
                self.server.shutdown()
            # 先返回200再关闭
            self.send_response(200)
            threading.Thread(target=kill_me_please).start()

        elif re.search('/api/get/*', self.path):
            record_id = self.path.split('/')[-1]
            if record_id in LocalData.records:
                self.send_response(200)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                # 以JSON格式返回数据,尽管POST用的是URL参数
                data = json.dumps(LocalData.records[record_id])
                print(f"getstatus {record_id}: {data}")
                self.wfile.write(data.encode('utf8'))
            else:
                self.send_response(404, 'Not Found: record does not exist')
        else:
            self.send_response(403)
        log("Server: GET:" + datetime.now().strftime("%d/%m/%Y %H:%M:%S.%f")[:-3])
        self.end_headers()

def Quits(reason="KeyboardInterrupt"):
    r = requests.get(f"http://{ServerIP}:{str(ServerPort)}/api/shutdown")
    log(f"{reason}; exiting: " + datetime.now().strftime("%d/%m/%Y %H:%M:%S.%f")[:-3])
    exit(1)
        
def log(msg="-----" + datetime.now().strftime("%d/%m/%Y %H:%M:%S.%f")[:-3] + "-----"):
    f = open("/var/log/TServer.log", "a")
    f.write(msg + '\n')
    f.close()
    
def UDPListener(sock):
    global ServerIP, ServerPort
    msg = ''
    headers = {"Content-Type": "application/json"}
    url = f"http://{ServerIP}:{str(ServerPort)}/api/set/txlink"
    while ServerThread.is_alive():
        data, addr = sock.recvfrom(96)
        data = data.decode("utf-8")
        if data == "Up and ok":
            msg = 'state=0'
        elif data == "Down, bad":
            msg = "state=1"
        r = requests.post(url, headers=headers, data=msg)
        print(f"updated: " + datetime.now().strftime("%d/%m/%Y %H:%M:%S.%f")[:-3])
        sock.close()
        
def main():
    global ServerIP, ServerPort, ServerThread
    signal.signal(signal.SIGINT, signal.default_int_handler)
    signal.signal(signal.SIGTERM, signal.default_int_handler)
            
    parser = argparse.ArgumentParser(description='TServer Process')
    parser.add_argument('ip', help='HTTP服务器IP')
    parser.add_argument('port', type=int, help='HTTP服务器监听端口')
    parser.add_argument('Tx_ip', help='TX网卡IP')
    parser.add_argument('Tx_port', type=int, help='TX监听端口')
    args = parser.parse_args()
            
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
    sock.bind((args.Tx_ip, args.Tx_port))
            
    ServerIP = args.ip
    ServerPort = args.port
    ServerThread = threading.Thread(target=run_srv) 
    ReceiverThread = threading.Thread(target=UDPListener, args=[sock,]) 
    try:
        ServerThread.start()
        ReceiverThread.start()
        ServerThread.join()
        ReceiverThread.join()
    except KeyboardInterrupt:
        sock.close()
        Quits()
    except RuntimeError:
        sock.close()
        Quits("RuntimeError")
    except OSError:
        sock.close()
        Quits("OSError")
    sock.close()
        
main()

排查建议

  • 检查Ubuntu系统的rp_filter配置:
    执行sysctl -a | grep rp_filter,若值为1(严格模式),内核可能丢弃来源IP与路由表不匹配的数据包。可临时执行sysctl -w net.ipv4.conf.all.rp_filter=0和sysctl -w net.ipv4.conf.<网卡名>.rp_filter=0测试,永久修改需编辑/etc/sysctl.conf。
  • 检查网卡多播/广播配置:
    执行ip link show <网卡名>确认是否开启多播功能;同时检查net.ipv4.conf.all.broadcast_igmp等相关内核参数。
  • 检查进程绑定地址:
    用netstat -ulpn查看UDP端口的绑定情况,确认监听脚本是否绑定了正确的网卡IP(而非127.0.0.1)。
  • 检查内核数据包过滤规则:
    即使关闭ufw,仍可能存在iptables/nftables规则残留,执行iptables -L -n和nft list ruleset检查是否有丢弃UDP数据包的规则。
  • 检查网卡驱动:
    因硬件一致仅单台异常,可能是网卡驱动版本或状态问题,尝试重新加载网卡驱动或更新驱动版本测试。

内容的提问来源于stack exchange,提问作者Roman M.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 11:18:28