我有一个异步UDP服务器类,其套接字绑定(bind)在IPAddress.Any上,我想知道接收到的数据包发送到(或接收到)哪个IPAddress。似乎我不能只使用Socket.LocalEndPoint属性,因为它总是返回0.0.0.0(这与它绑定(bind)在一起是有道理的...)。
这是我当前正在使用的代码中有趣的部分:
private Socket udpSock;
private byte[] buffer;
public void Starter(){
//Setup the socket and message buffer
udpSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
udpSock.Bind(new IPEndPoint(IPAddress.Any, 12345));
buffer = new byte[1024];
//Start listening for a new message.
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock);
}
private void DoReceiveFrom(IAsyncResult iar){
//Get the received message.
Socket recvSock = (Socket)iar.AsyncState;
EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP);
byte[] localMsg = new byte[msgLen];
Array.Copy(buffer, localMsg, msgLen);
//Start listening for a new message.
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock);
//Handle the received message
Console.WriteLine("Recieved {0} bytes from {1}:{2} to {3}:{4}",
msgLen,
((IPEndPoint)clientEP).Address,
((IPEndPoint)clientEP).Port,
((IPEndPoint)recvSock.LocalEndPoint).Address,
((IPEndPoint)recvSock.LocalEndPoint).Port);
//Do other, more interesting, things with the received message.
}
如前所述,它总是打印一行:
我希望它像是:
预先感谢您对此有任何想法!
- 亚当
更新
好吧,我找到了一个解决方案,尽管我不喜欢它...基本上,不是打开绑定(bind)到IPAddress的单个udp套接字,而是为每个可用的IPAddress创建一个唯一的套接字。因此,新的Starter函数如下所示:
public void Starter(){
buffer = new byte[1024];
//create a new socket and start listening on the loopback address.
Socket lSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
lSock.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
EndPoint ncEP = new IPEndPoint(IPAddress.Any, 0);
lSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ncEP, DoReceiveFrom, lSock);
//create a new socket and start listening on each IPAddress in the Dns host.
foreach(IPAddress addr in Dns.GetHostEntry(Dns.GetHostName()).AddressList){
if(addr.AddressFamily != AddressFamily.InterNetwork) continue; //Skip all but IPv4 addresses.
Socket s = new Socket(addr.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
s.Bind(new IPEndPoint(addr, 12345));
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
s.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, s);
}
}
这只是为了说明概念,此代码的最大问题是,每个套接字都试图使用相同的缓冲区...这通常是个坏主意...
必须对此有一个更好的解决方案。我的意思是,源和目标是UDP数据包头的一部分!哦,好吧,我想我会继续研究,直到有更好的东西为止。
最佳答案
我只是有同样的问题。我看不到使用ReceiveFrom
或其异步变体检索接收到的数据包的目标地址的方法。
但是...如果使用ReceiveMessageFrom
或其变体,您将获得IPPacketInformation
(通过引用ReceiveMessageFrom
和EndReceiveMessageFrom
或作为SocketAsyncEventArgs
的属性传递给ReceiveMessageFromAsync
的回调)。该对象将包含接收数据包的IP地址和接口(interface)号。
(请注意,此代码尚未经过测试,因为我使用了ReceiveMessageFromAsync
而不是假冒的Begin/End调用。)
private void ReceiveCallback(IAsyncResult iar)
{
IPPacketInformation packetInfo;
EndPoint remoteEnd = new IPEndPoint(IPAddress.Any, 0);
SocketFlags flags = SocketFlags.None;
Socket sock = (Socket) iar.AsyncState;
int received = sock.EndReceiveMessageFrom(iar, ref flags, ref remoteEnd, out packetInfo);
Console.WriteLine(
"{0} bytes received from {1} to {2}",
received,
remoteEnd,
packetInfo.Address
);
}
注意,显然,应该在设置
SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true)
之前调用Bind
作为设置套接字的一部分。 ... ReceiveMessageFrom ...方法将为您设置它,但是设置该选项后,您可能只会看到Windows看到的任何数据包的有效信息。 (实际上,这不是什么大问题-但是何时/如果发生过,原因将是一个谜。最好完全避免它。)关于c# - C#UDP套接字: Get receiver address,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4147542/