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

NodeMCU与Unity UDP通信卡顿修复及可调用SendData方法求助

问题根因分析
  • 核心冻结原因:Socket.ReceiveFrom是同步阻塞方法,在Unity主线程的Update生命周期中调用时,没有收到UDP包就会一直阻塞等待,直接卡住主线程导致Unity无响应
  • 其他错误点:
    1. Unity代码的Update末尾主动调用了server.Close(),首次帧运行后Socket就被销毁,后续发送功能完全失效
    2. 目标IP配置错误:NodeMCU固定IP为192.168.43.20,Unity代码中写为192.162.43.209,网段不匹配无法通信
    3. NodeMCU回包逻辑未放在收到包的判断分支内,无连接时调用Udp.remoteIP()会出现空地址异常
修复代码

第一步:修复NodeMCU端代码

把回包逻辑移到收到包的判断块内,避免空地址错误:

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

const char* ssid = "Epic SSID";
const char* password = "EpicPassword";

WiFiUDP Udp;
unsigned int port = 25666;
char packet[255];

IPAddress ip(192, 168, 43, 20);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

void setup()
{
    Serial.begin(115200);
    Serial.println();

    WiFi.hostname("YVRB-01");
    WiFi.config(ip, gateway, subnet);

    Serial.printf("Connecting to %s ", ssid);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    }

    Serial.println("Connection Successful");
    Udp.begin(port);
    Serial.printf("Listener started at IP %s, at port %d", WiFi.localIP().toString().c_str(), port);
}

void loop()
{
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
      Serial.printf("Received %d bytes from %s, port %d", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
      int len = Udp.read(packet, 255);
      if (len > 0)
      {
          packet[len] = 0;
      }
      Serial.printf("UDP packet contents: %s", packet);
      Serial.println();
      // 回包逻辑移到此处,仅在收到包时回复
      Udp.beginPacket (Udp.remoteIP(), Udp.remotePort());
      Udp.write("Epic message");
      Udp.endPacket();
  }
  delay(300);
}

第二步:修复Unity端代码

改用异步接收+非阻塞逻辑,保留SendData调用能力,不会卡住主线程:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using System.Threading;

public class UdpCommunicator : MonoBehaviour
{
    [Header("UDP配置")]
    public string targetIp = "192.168.43.20";
    public int targetPort = 25666;
    public int localListenPort = 25667;

    private Socket udpSocket;
    private IPEndPoint targetEndPoint;
    private Thread receiveThread;
    private byte[] receiveBuffer = new byte[1024];
    private bool isRunning = false;

    void Start()
    {
        // 初始化Socket
        udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        targetEndPoint = new IPEndPoint(IPAddress.Parse(targetIp), targetPort);
        // 绑定本地监听端口用于接收NodeMCU回包
        udpSocket.Bind(new IPEndPoint(IPAddress.Any, localListenPort));
        
        isRunning = true;
        // 接收逻辑放到独立子线程,不阻塞主线程
        receiveThread = new Thread(ReceiveLoop);
        receiveThread.IsBackground = true;
        receiveThread.Start();

        // 发送初始连接消息
        SendData("I am connected");
    }

    // 接收循环 运行在子线程
    private void ReceiveLoop()
    {
        EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        while (isRunning)
        {
            try
            {
                int recvLength = udpSocket.ReceiveFrom(receiveBuffer, ref remoteEndPoint);
                string receivedMsg = Encoding.ASCII.GetString(receiveBuffer, 0, recvLength);
                Debug.Log($"收到UDP消息,来源:{remoteEndPoint},内容:{receivedMsg}");
            }
            catch (SocketException e)
            {
                // 正常关闭时忽略异常
                if (isRunning) Debug.LogError($"UDP接收错误:{e.Message}");
            }
            Thread.Sleep(10);
        }
    }

    // 对外公开的发送方法,直接调用即可
    public void SendData(string message)
    {
        if (udpSocket == null || !isRunning) return;
        byte[] sendData = Encoding.ASCII.GetBytes(message);
        udpSocket.SendTo(sendData, sendData.Length, SocketFlags.None, targetEndPoint);
        Debug.Log($"已发送UDP消息:{message}");
    }

    // 释放资源
    private void OnDestroy()
    {
        isRunning = false;
        receiveThread?.Join(100);
        udpSocket?.Close();
        udpSocket?.Dispose();
    }
}
使用说明
  1. 确认NodeMCU和运行Unity的设备连接在同一个WiFi下
  2. 把Unity代码挂到场景任意活跃GameObject上,检查Inspector面板的目标IP和端口是否和NodeMCU的配置一致
  3. 任意逻辑中获取UdpCommunicator组件后,调用SendData("自定义内容")即可发送消息
  4. 运行后Unity控制台会打印收发消息日志,NodeMCU的串口也会输出收到的内容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:36:03