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

Unity中C# UDP发送正常但无法接收的问题求助

解决Unity UDP无法接收PLC数据包的问题

看起来你已经把网络层面的排查做的很到位了——端口被Unity占用、Wireshark能抓到包、本地回环能接收,这些都说明核心的网络链路是通的,问题大概率出在套接字的配置或者Unity线程/环境的细节上。我给你梳理几个针对性的排查和修复方向:

1. 明确绑定本地以太网IP,避免多网卡路由歧义

你当前用new UdpClient(8052,AddressFamily.InterNetwork)默认绑定的是0.0.0.0(所有可用网络接口),但在直连以太网的场景下,明确绑定到你的笔记本以太网IP(192.168.0.41)能避免系统在多网卡(比如还有Wi-Fi)下的路由优先级问题。修改绑定逻辑:

// 替换ReceiveData里的UdpClient初始化代码
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.41"), 8052);
using (var udpClient = new UdpClient(localEndPoint))
{
    // 后续接收逻辑...
}

2. 修复线程与Unity主线程的交互问题

你在接收线程里频繁调用print,但Unity的print是主线程专属API,跨线程频繁调用可能会引发隐式的线程阻塞或者数据丢失。建议改用线程安全的队列存储接收数据,在Update里统一处理日志和数据:

// 新增线程安全队列存储接收数据
private ConcurrentQueue<byte[]> _receivedDataQueue = new ConcurrentQueue<byte[]>();

private void ReceiveData()
{
    IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.41"), 8052);
    using (var udpClient = new UdpClient(localEndPoint))
    {
        udpClient.EnableBroadcast = true; // 确保支持广播(如果PLC用广播发送)
        while (canReceive)
        {
            try
            {
                IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                var receivedResults = udpClient.Receive(ref remoteEndPoint);
                _receivedDataQueue.Enqueue(receivedResults);
                // 这里用Debug.LogWarning或者直接记录到线程安全的日志变量,不要用print
            }
            catch (SocketException ex)
            {
                if (ex.SocketErrorCode != SocketError.Interrupted)
                {
                    Debug.LogError($"UDP接收错误: {ex.Message}");
                }
            }
        }
    }
}

// 在Update里处理队列数据
void Update()
{
    while (_receivedDataQueue.TryDequeue(out byte[] data))
    {
        Debug.Log($"成功接收{data.Length}字节数据");
        // 解析两个float的逻辑
        if (data.Length == 8)
        {
            float val1 = BitConverter.ToSingle(data, 0);
            float val2 = BitConverter.ToSingle(data, 4);
            Debug.Log($"解析结果: {val1}, {val2}");
        }
    }
    // 你的其他Update逻辑...
}

3. 添加套接字关键选项配置

尝试设置几个UDP套接字的优化选项,避免因缓冲区过小或者协议特性导致丢包:

// 在UdpClient初始化后添加
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
udpClient.Client.ReceiveBufferSize = 1024 * 1024; // 增大接收缓冲区到1MB

4. 确保线程能被安全终止

在脚本销毁时要正确终止接收线程,避免套接字资源泄漏:

void OnDestroy()
{
    canReceive = false;
    receiveThread?.Join(1000); // 等待线程优雅终止
    receiveThread = null;
}

5. 用最小化脚本排除第三方干扰

你当前项目里导入了PlayMaker,有可能是第三方插件的网络钩子或者线程管理影响了UDP接收。可以新建一个空Unity项目,只导入下面这个最小化测试脚本,再测试PLC的接收:

using System;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
using System.Threading;
using System.Collections.Concurrent;

public class MinimalUDPTest : MonoBehaviour
{
    private Thread _receiveThread;
    private UdpClient _udpClient;
    private bool _isRunning;
    private ConcurrentQueue<byte[]> _dataQueue = new ConcurrentQueue<byte[]>();

    public int ListenPort = 8052;
    public string LocalIP = "192.168.0.41";

    void Start()
    {
        _isRunning = true;
        _receiveThread = new Thread(ReceiveLoop) { IsBackground = true };
        _receiveThread.Start();
    }

    void ReceiveLoop()
    {
        try
        {
            IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(LocalIP), ListenPort);
            _udpClient = new UdpClient(localEP);
            _udpClient.EnableBroadcast = true;

            while (_isRunning)
            {
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
                byte[] data = _udpClient.Receive(ref remoteEP);
                _dataQueue.Enqueue(data);
                Debug.Log($"从{remoteEP.Address}收到{data.Length}字节");
            }
        }
        catch (SocketException ex)
        {
            if (_isRunning) Debug.LogError($"UDP错误: {ex.Message}");
        }
        finally
        {
            _udpClient?.Close();
        }
    }

    void Update()
    {
        while (_dataQueue.TryDequeue(out byte[] data))
        {
            if (data.Length == 8)
            {
                float v1 = BitConverter.ToSingle(data, 0);
                float v2 = BitConverter.ToSingle(data, 4);
                Debug.Log($"解析值: {v1:F2}, {v2:F2}");
            }
        }
    }

    void OnDestroy()
    {
        _isRunning = false;
        _udpClient?.Close();
        _receiveThread?.Join(1000);
    }
}

最后几个排查点

  • 确认PLC发送的目标IP是192.168.0.41,端口是8052,没有误设为广播地址(如果是广播,上面的脚本已经开启了广播接收)
  • 检查Windows防火墙的出站规则,虽然你开放了入站,但有时候系统会限制UDP的出站响应(不过你的Wireshark能看到Unity发的包,这条可能性较低)
  • 确认笔记本的以太网适配器没有开启任何特殊的网络优化(比如QoS、节能模式)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:36:55