当前位置:  开发笔记 > 编程语言 > 正文

C#UDP套接字:获取接收者地址

如何解决《C#UDP套接字:获取接收者地址》经验,为你挑选了1个好方法。

我有一个异步UDP服务器类,其中一个套接字绑定在IPAddress.Any上,我想知道收到的数据包被发送到哪个IP地址(...或接收到).看来我不能只使用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.
}

如前所述,这总是打印一条线,如:

从127.0.0.1:1678到0.0.0.0:12345收到32个字节

而且我希望它是这样的:

从127.0.0.1:1678到127.0.0.1:12345收到32个字节

在此先感谢您对此的任何想法! - 亚当

UPDATE

好吧,我找到了一个解决方案,虽然我不喜欢它...基本上,我没有打开绑定到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数据包头的一部分!哦,好吧,我想我会继续这样做,直到有更好的东西.



1> cHao..:

我刚遇到同样的问题.我没有看到使用ReceiveFrom或其异步变体的方法来检索接收数据包的目标地址.

但是......如果你使用ReceiveMessageFrom它或它的变种,你将得到一个IPPacketInformation(通过引用ReceiveMessageFromEndReceiveMessageFrom,或作为SocketAsyncEventArgs传递给你的回调的属性ReceiveMessageFromAsync).该对象将包含接收数据包的IP地址和接口号.

(注意,此代码尚未经过测试,因为我使用的ReceiveMessageFromAsync不是伪造的假开始/结束调用.)

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看到的任何数据包的有效信息.(在实践中,这不是一个问题 - 但是如果/如果它曾经发生过,原因将是一个谜.最好完全防止它.)

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有