发送 UDP 消息有效,接收无效 - C# on Unity3d
Sending UDP messages works, receiving not - C# on Unity3d
你好,
我正在尝试在 Unity3d 中建立 UDP 连接,过去几天它一直让我头疼:
我 运行ning 的 Unity 脚本应该可以接收并可能在将来发送 UDP 消息。
在 Unity 旁边,我使用 Wireshark 来跟踪数据包并 PacketSender 生成和接收 UDP 消息。
消息的来源是每秒发送一个包的PLC,包含两个浮点数(8字节)用于测试。
PLC IP 是 192.168.0.1
,它通过以太网直接连接到笔记本电脑 运行ning Unity。 (没有交换机,没有路由器)
我的以太网端口有 IP 192.168.0.41
,消息通过端口 8052 传入。
我可以通过以下方式在 Wireshark 中看到的内容:
- 从 PLC 到达 Unity 的包
- 从 Unity 离开到 PLC 的包
- 包具有预期的结构
我可以在 PacketSender 中看到/执行的操作:
- 从 PLC 到达的包(通过端口 8052)
- 向 Wireshark 中可见的 PLC 发送消息
- 通过在此处接收包,可以肯定地说防火墙端口 window 有效。
- 如果我已经启动了 Unity 接收脚本,我将无法使用 PacketSender 接收包...
... 这应该是一个指标,Unity UDP 套接字已启动并且 运行ning,希望能吞下消息。
如果我调用 netstat -aon
,我可以在预期的端口和 IP 上看到 Unity UPD 进程;
0.0.0.0:8052
或 192.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);
我试过了...
- ...接收同步或异步消息
- ...到运行 主线程或后台线程中的接收循环
- ...到 en-/disable 客户端阻塞
- ...将客户端绑定到 IP 或将其保留在 IPAddress.Any
- ...关闭以太网端口上的 HyperV 交换机(仍然关闭)
- ...在防火墙中打开相关端口
- ...重启笔记本电脑
- ...关于我在任何论坛中可以找到的所有解决方案。
感觉是 C# 套接字和 Step7 套接字使用不同的 UDP,或者 C# 套接字在接收端没有按预期运行。
包真的到了socket家门口就忽略了
设置规范:
PLC:CPU315-2 PN/DP
笔记本电脑:戴尔 Latitude,i5,8GB 内存,Win10 企业版,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();
}
}
我知道代码中缺少注释,但正如您可能已经猜到的那样,代码最近发生了很大变化。
感谢您的帮助。
所以在经历了一段非常令人沮丧的旅程之后,我找到了一个虽然不太好但可以解决问题的解决方法:
我写了一个 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
是否您的插座是 运行。
- 完成:检查您的防火墙设置。
如果您想从外部源接收,您需要在防火墙上允许 Unity 或禁用防火墙。防火墙阻止统一编辑器与外部源的连接,这就是为什么您可以发送数据但无法接收数据的原因。如果你构建你的项目,你的代码将会工作,因为它会首先询问你 运行
你好,
我正在尝试在 Unity3d 中建立 UDP 连接,过去几天它一直让我头疼:
我 运行ning 的 Unity 脚本应该可以接收并可能在将来发送 UDP 消息。 在 Unity 旁边,我使用 Wireshark 来跟踪数据包并 PacketSender 生成和接收 UDP 消息。
消息的来源是每秒发送一个包的PLC,包含两个浮点数(8字节)用于测试。
PLC IP 是 192.168.0.1
,它通过以太网直接连接到笔记本电脑 运行ning Unity。 (没有交换机,没有路由器)
我的以太网端口有 IP 192.168.0.41
,消息通过端口 8052 传入。
我可以通过以下方式在 Wireshark 中看到的内容:
- 从 PLC 到达 Unity 的包
- 从 Unity 离开到 PLC 的包
- 包具有预期的结构
我可以在 PacketSender 中看到/执行的操作:
- 从 PLC 到达的包(通过端口 8052)
- 向 Wireshark 中可见的 PLC 发送消息
- 通过在此处接收包,可以肯定地说防火墙端口 window 有效。
- 如果我已经启动了 Unity 接收脚本,我将无法使用 PacketSender 接收包...
... 这应该是一个指标,Unity UDP 套接字已启动并且 运行ning,希望能吞下消息。
如果我调用 netstat -aon
,我可以在预期的端口和 IP 上看到 Unity UPD 进程;
0.0.0.0:8052
或 192.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);
我试过了...
- ...接收同步或异步消息
- ...到运行 主线程或后台线程中的接收循环
- ...到 en-/disable 客户端阻塞
- ...将客户端绑定到 IP 或将其保留在 IPAddress.Any
- ...关闭以太网端口上的 HyperV 交换机(仍然关闭)
- ...在防火墙中打开相关端口
- ...重启笔记本电脑
- ...关于我在任何论坛中可以找到的所有解决方案。
感觉是 C# 套接字和 Step7 套接字使用不同的 UDP,或者 C# 套接字在接收端没有按预期运行。 包真的到了socket家门口就忽略了
设置规范: PLC:CPU315-2 PN/DP 笔记本电脑:戴尔 Latitude,i5,8GB 内存,Win10 企业版,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();
}
}
我知道代码中缺少注释,但正如您可能已经猜到的那样,代码最近发生了很大变化。
感谢您的帮助。
所以在经历了一段非常令人沮丧的旅程之后,我找到了一个虽然不太好但可以解决问题的解决方法:
我写了一个 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
是否您的插座是 运行。 - 完成:检查您的防火墙设置。
如果您想从外部源接收,您需要在防火墙上允许 Unity 或禁用防火墙。防火墙阻止统一编辑器与外部源的连接,这就是为什么您可以发送数据但无法接收数据的原因。如果你构建你的项目,你的代码将会工作,因为它会首先询问你 运行