繁体   English   中英

发送 UDP 消息有效,接收无效 - Unity3d 上的 C#

[英]Sending UDP messages works, receiving not - C# on Unity3d

你好,

我正在尝试在 Unity3d 中设置 UDP 连接,过去几天它一直给我带来一些麻烦:

我正在运行的 Unity 脚本应该接收并可能在将来发送 UDP 消息。 在 Unity 旁边,我使用 Wireshark 来跟踪数据包和PacketSender来生成和接收 UDP 消息。

消息的来源是一个 PLC,它每秒发送一个包,其中包含两个用于测试的浮点数(8 个字节)。 PLC IP 为192.168.0.1 ,它通过以太网直接连接到运行 Unity 的笔记本电脑。 (没有交换机,没有路由器)

我的以太网端口的 IP 为192.168.0.41 ,消息通过端口 8052 传入。

我可以通过以下方式在 Wireshark 中看到的内容:

  • 包从 PLC 到达 Unity
  • 从 Unity 到 PLC 的包
  • 包具有预期的结构

我可以在 PacketSender 中看到/做的事情:

  • 来自 PLC 的包(通过端口 8052)
  • 向 Wireshark 中可见的 PLC 发送消息
  • 通过在此处接收包,也应该可以肯定地说防火墙端口窗口有效。
  • 如果我已经启动了我的 Unity 接收脚本,我将无法使用 PacketSender 接收包...

...这应该是一个指标,表明 Unity UDP 套接字已启动并正在运行,希望能够吞下消息。 如果我调用netstat -aon我可以在预期的端口和 IP 处看到 Unity UPD 进程; 0.0.0.0:8052192.168.0.41:8052 ,取决于它的创建方式。 我也可以看到没有其他进程使用相同的端口。

但不起作用的是在我的 Unity 脚本中实际接收和使用数据。

有效的是从另一个 Unity 脚本接收通过本地 IP 127.0.0.1 发送的数据。

到目前为止,我已经尝试了几种创建套接字的方法:

var udpClient = new UdpClient(8052,AddressFamily.InterNetwork)
var udpClient = new UdpClient(8052)
UdpClient udpClient = new UdpClient(8052,AddressFamily.InterNetwork)
var udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

我试过了...

  • ...同步或异步接收消息
  • ...在主线程或后台线程中运行接收循环
  • ...启用/禁用客户端的阻止
  • ...将客户端绑定到 IP 或将其保留在 IPAddress.Any 上
  • ...关闭我在以太网端口上的 HyperV 交换机(仍然关闭)
  • ...打开防火墙中的相关端口
  • ...重新启动笔记本电脑
  • ...关于我可以在任何论坛中找到的所有解决方案。

感觉就像 C# 套接字和 Step7 套接字使用不同的 UDP,或者 C# 套接字在接收端没有按预期运行。 包真的在插座的门口,它忽略了它。


设置规格:PLC:CPU315-2 PN/DP 笔记本电脑:Dell Latitude,i5,8GB RAM,Win10 Enterprise,64 位 Unity:Unity 2017.3.1f1,只有 PlayMaker


当前测试代码:

using System; using System.Net; using System.Net.Sockets; using UnityEngine; using System.Threading; public class UDPReceive03 : MonoBehaviour { Thread receiveThread; public UdpClient socket; private bool canReceive; public static bool messageReceived; public String statusThread; public int UDP_LISTEN_PORT; private int alive; // Use this for initialization void Start() { UDP_LISTEN_PORT = 8052; print("started"); canReceive = true; messageReceived = false; alive = 0; receiveThread = new Thread(new ThreadStart(ReceiveData)); receiveThread.IsBackground = true; receiveThread.Start(); } // Update is called once per frame void Update() { // I know the code below is ugly, but that was my rebellion agains the situation statusThread = (canReceive) ? "Waiting" : "Busy"; if (alive % 180 == 0) sendResponse(1); alive = (alive<180) ? alive + 1 : 1; } private void ReceiveData() { using (var udpClient = new UdpClient(8052,AddressFamily.InterNetwork)) { int loggingEvent = 0; while (true) { print("started to receive"); IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); var receivedResults = udpClient.Receive(ref remoteEndPoint); loggingEvent += receivedResults.Length; print("Success, received " + loggingEvent.ToString() + " bytes."); sendResponse(loggingEvent); } } } private void sendResponse(int count) { socket = new UdpClient(8051); // sending data IPEndPoint target = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 2000); // send a couple of sample messages: for (int num = 1; num <= count; num++) { byte[] message = new byte[num]; socket.Send(message, message.Length, target); } socket.Close(); } }

我知道代码中缺少注释,但正如您可能已经猜到的,代码最近发生了很大变化。

感谢您的帮助。

如果您想从外部来源接收,您需要在防火墙上允许 Unity 或禁用防火墙。 防火墙阻止了与外部源的统一编辑器连接,这就是您可以发送数据但无法接收数据的原因。 如果你构建你的项目,你的代码就会工作,因为它会在第一次运行时询问你

在此处输入图片说明

因此,在经历了一次非常令人沮丧的旅程之后,我发现了一个不太好但可以完成工作的解决方法:

我编写了一个 python 脚本,它打开一个套接字,接收外部数据并通过本地 IP 将其转发到 Unity。 这有效。

这是代码:

# Import libraies
import socket
import time

# Set send IP adress and port
UDP_IP = "127.0.0.1"
UDP_PORT_Rec = 8052
UDP_PORT_Unity = 8055

print("Receiving on Port:" + str(UDP_PORT_Rec))
print("Sending to IP:" + UDP_IP + ":" + str(UDP_PORT_Unity))

# Set socket to send udp messages and bind port
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind(('',UDP_PORT_Rec));

## Keep sending message from file location
while True:
    data, addr = sock.recvfrom(1024) #buffer size, hopefully no problem if too big
    print("Received")

    sock.sendto(data, (UDP_IP, UDP_PORT_Unity))
    print("Send")

对您排除故障有用的工具:

  • 安装Wireshark 它可能是跟踪 Internet 流量的最佳工具。 在 Wireshark 中可见的包对于普通应用程序可能不可见!
  • 使用Packet Sender生成和接收流量。 该应用程序使用一种基本方法来接收包 - 如果可以,那么您的程序也应该可以。
  • 如果您的套接字正在运行,请使用netstat -aon检查。
  • 完成:检查您的防火墙设置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM