我有一个异步UDP服务器类,绑定在IPAddress.Any上的套接字,我想知道接收到的数据包被发送到哪个IPAddress(或者在哪个IPAddress上接收到)。看起来我不能仅仅使用Socket.LocalEndPoint属性,因为它总是返回0.0.0.0(这是有道理的,因为它绑定在那里...)。
这是我目前正在使用的代码的有趣部分:
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.
}
如前所述,这段代码总是打印出以下一行信息:
Received 32 bytes from 127.0.0.1:1678 to 0.0.0.0:12345
而我希望它变成这样:
Received 32 bytes from 127.0.0.1:1678 to 127.0.0.1:12345
谢谢您提前的任何想法! --Adam
更新
好吧,我找到了一个解决方案,虽然我不太喜欢它... 基本上,我不再打开一个绑定到 IPAddress.Any 的 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数据包头的一部分!哦,好吧,我想我会继续使用这个方法,直到有更好的解决方案。
SocketAsyncEventArgs
,将处理程序附加到其Completed
事件,然后将对象传递给ReceiveMessageFromAsync
即可。 - cHao