无法使用UdpClient捕获收到的数据报
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无法使用UdpClient捕获收到的数据报相关的知识,希望对你有一定的参考价值。
我正在尝试向设备发送UDP命令并从同一设备接收UDP响应。发送工作正常。我可以看到数据报离开(通过WireShark)。我还可以看到数据报从设备返回(再次通过WireShark)。命令离开和响应接收之间的周转时间约为15毫秒。
码
Byte[] button_click(Byte[] command)
{
// Device exists at a particular IP address and listens for UDP commands on a particular port
IPEndPoint SendingEndpoint = new IPEndPoint(DEVICE_IP, DEVICE_PORT);
// Device always sends from port 32795 to whatever port the command originated from on my machine
IPEndPoint ReceivingEndpoint = new IPEndPoint(DEVICE_IP, 32795);
// Sending client
sendingClient = new UdpClient();
sendingClient.Connect(SendingEndpoint);
// Receiving client
receivingClient = new UdpClient();
receivingClient.Client.ReceiveTimeout = RECEIVE_TIMEOUT; // timeout after 4 seconds
receivingClient.Connect(receivingEndpoint);
// Send command and wait for response
Byte[] response = null;
try
{
sendingClient.Connect(DEVICE_IP, DEVICE_PORT);
sendingClient.Send(command, command.Length);
response = receivingClient.Receive(ref receivingEndpoint);
}
catch (SocketException e)
{
// If we timeout, discard SocketException and return null response
}
return response;
}
问题
我无法在我的应用程序中捕获收到的数据报。当我运行上面的代码时,我得到以下异常:
“连接尝试失败,因为连接方在一段时间后没有正确响应,或者建立的连接失败,因为连接的主机无法响应。”
StackOverflow上有类似的帖子,但它们似乎都没有解决我的情况。我已经验证我的数据包没有被防火墙扫除。
我究竟做错了什么?
答案
我解决了这个问题。解决方案需要两件事:
- 发送和接收客户端必须使用相同的本地端口
- 发送客户端必须使用
IPEndPoint
声明的IPAddress.Any
,接收客户端必须使用我本地机器的确切IP地址声明的IPEndPoint
码
// Create endpoints
IPEndPoint DeviceEndPoint = new IPEndPoint(DEVICE_IP, DEVICE_PORT);
IPEndPoint localEndPointAny = new IPEndPoint(IPAddress.Any, LOCAL_PORT); // helps satisfy point 2
IPEndPoint localEndPointExplicit = new IPEndPoint(IPAddress.Parse(GetLocalIPAddress()), LOCAL_PORT); // helps satisfy point 2
IPEndPoint incomingEndPoint = null; // Later populated with remote sender's info
// Create sending client
UdpClient sendingClient = new UdpClient();
sendingClient.ExclusiveAddressUse = false; // Going to use same port for outgoing and incoming (helps satisfy point 1)
sendingClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // helps satisfy point 1
sendingClient.Client.Bind(localEndPointAny); // Any outgoing IP address will do
// Create receiving client
UdpClient receivingClient = new UdpClient();
receivingClient.Client.ReceiveTimeout = RECEIVE_TIMEOUT; // 4000 milliseconds
receivingClient.ExclusiveAddressUse = false; // Going to use same port for outgoing and incoming (helps satisfy point 1)
receivingClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // helps satisfy point 1
receivingClient.Client.Bind(localEndPointExplicit); // Must explicitly give machine's outgoing IP address
获取本地IP地址can be found here的代码。
另一答案
如果您使用sendingClient接收,那么您可以获得正确的消息。原因是IP由Host + Port + Protocol组成,当发送点连接到设备并发送消息时,设备接收端点,UDP与发送端点配对。当接收客户端尝试接收消息时,由于UDP是对等端,并且接收客户端的端口必须与发送客户端不同,因此接收客户端什么也得不到,因此没有任何事情发生。以下是我的示例代码供您参考。
IPAddress address;
IPAddress.TryParse("127.0.0.1", out address);
IPEndPoint recPoint = new IPEndPoint(address, 13154);
// IPEndPoint sendPoint = new IPEndPoint(address, 9999);
UdpClient send = new UdpClient(9999);
send.Connect(recPoint);
Byte[] response = null;
Byte[] command = System.Text.Encoding.Default.GetBytes("NO one");
try
{
send.Send(command, command.Length);
response = send.Receive(ref recPoint);
}
catch(Exception ex) {
Console.WriteLine(ex.ToString());
}
根据Alex的回答,我更新了一个完整的示例代码供参考。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Net;
namespace console
{
class Program
{
static void Main(string[] args)
{
IPAddress address;
IPAddress.TryParse("192.168.14.173", out address);
IPEndPoint recPoint = new IPEndPoint(address, 13154);
IPEndPoint recAnyPoint = new IPEndPoint(IPAddress.Any, 13154);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.14.174"), 13154);
// IPEndPoint sendPoint = new IPEndPoint(address, 9999);
UdpClient send = new UdpClient();
send.ExclusiveAddressUse = false;
// no need to use the low level socketoption
// send.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
send.Client.Bind(recAnyPoint);
send.Connect(ipPoint);
UdpClient receive = new UdpClient();
receive.ExclusiveAddressUse = false;
// receive.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
receive.Client.Bind(recPoint);
receive.Connect(ipPoint);
Byte[] response = null;
Byte[] command = System.Text.Encoding.Default.GetBytes("NO one");
try
{
send.Send(command, command.Length);
response = receive.Receive(ref ipPoint);
Console.WriteLine(System.Text.Encoding.Default.GetString(response));
}
catch(Exception ex) {
Console.WriteLine(ex.ToString());
}
}
}
}
以上是关于无法使用UdpClient捕获收到的数据报的主要内容,如果未能解决你的问题,请参考以下文章