C#UDP套接字:获取接收器地址 [英] C# UDP Socket: Get receiver address

查看:256
本文介绍了C#UDP套接字:获取接收器地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个异步的UDP服务器类绑定在IPAddress.Any一个插座上,我想知道哪些ip地址接收的数据包被发送至(......或收到)。看来,我不能只用Socket.LocalEndPoint属性,它总是返回0.0.0.0(这是有道理的,因为它是必然的...)。



这里是我目前使用的代码有趣的部分:

 专用插座udpSock; 
私人字节[]缓冲区;
公共无效启动(){
//设置插座和消息缓冲区
udpSock =新的Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
udpSock.Bind(新IPEndPoint(IPAddress.Any,12345));
缓冲区=新的字节[1024];

//开始监听新的消息。
端点newClientEP =新IPEndPoint(IPAddress.Any,0);
udpSock.BeginReceiveFrom(缓冲,0,buffer.Length,SocketFlags.None,裁判newClientEP,DoReceiveFrom,udpSock);
}

私人无效DoReceiveFrom(IAsyncResult的IAR){
//获取收到的消息。
插槽recvSock =(插座)iar.AsyncState;
端点clientEP =新IPEndPoint(IPAddress.Any,0);
INT msgLen = recvSock.EndReceiveFrom(IAR,楼盘clientEP);
字节[] = localMsg新的字节[msgLen]
Array.Copy(缓冲液,localMsg,msgLen);

//开始监听新的消息。
端点newClientEP =新IPEndPoint(IPAddress.Any,0);
udpSock.BeginReceiveFrom(缓冲,0,buffer.Length,SocketFlags.None,裁判newClientEP,DoReceiveFrom,udpSock);

//处理接收到的消息
Console.WriteLine(收到{0}从字节{1}:{2}到{3} {4},
msgLen,
((IPEndPoint)clientEP)。地址,
((IPEndPoint)clientEP).Port,
((IPEndPoint)recvSock.LocalEndPoint)。地址,
((IPEndPoint )recvSock.LocalEndPoint).Port);
//做其他的,更有趣的,用的东西收到的消息。
}

正如前面提到的这始终打印像行:

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



和我想它是这样的:

收到32个字节127.0 .0.1:1678年至127.0.0.1:12345



谢谢,提前,有这方面的想法!
--Adam



更新



好吧,我发现了一个解决方案,但我不喜欢它...基本上,而不是打开势必IPAddress.Any一个UDP套接字,我创造一切可以利用的ip地址独特的插座。那么,新入门的功能如下:

 公共无效启动(){
缓冲区=新的字节[1024] ;

//创建一个新的socket,并开始侦听环回地址。
插槽lSock =新的Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
lSock.Bind(新IPEndPoint(IPAddress.Parse(127.0.0.1),12345);

端点NCEP =新IPEndPoint(IPAddress.Any,0);
lSock.BeginReceiveFrom(缓冲,0,buffer.Length,SocketFlags.None,裁判NCEP,DoReceiveFrom,lSock);

//创建一个新的socket并开始听每个ip地址的DNS主机$。 b $ b的foreach(ip地址地址在Dns.GetHostEntry(Dns.GetHostName())AddressList中。){
如果(addr.AddressFamily = AddressFamily.InterNetwork!)继续; //跳过所有,但IPv4地址$ b $。 b
插槽S =新的Socket(addr.AddressFamily,SocketType.Dgram,ProtocolType.Udp);
s.Bind(新IPEndPoint(地址,12345));

端点newClientEP =新IPEndPoint(IPAddress.Any,0);
s.BeginReceiveFrom(缓冲液,0,buffer.Length,SocketFlags.None,裁判newClientEP,DoReceiveFrom,S);
}
}

这是只是为了说明这一概念,以作为此代码最大的问题,是每个插座试图用同样的缓冲......这通常是一个坏主意...



必须有一个更好的解决这个;我的意思是,源和目标为UDP数据报头的一部分!噢,我想我会用这个去,直到有更好的东西。


解决方案

我刚刚有同样的问题。我不明白的方式,使用 ReceiveFrom 或它的异步变种,检索接收的数据包的目的地址。



不过...如果你使用 ReceiveMessageFrom 或其变体,您将获得 IPPacketInformation (由一个参考为 ReceiveMessageFrom EndReceiveMessageFrom ,或作为一个属性的SocketAsyncEventArgs 传递给你的回调 ReceiveMessageFromAsync )。该对象将包含其中,接收到数据包的IP地址和端口号。



(注意,这个代码没有经过测试,为我所用 ReceiveMessageFromAsync 而非fakey仿开始/结束通话。)

 私人无效ReceiveCallback(IAsyncResult的IAR )
{
IPPacketInformation packetInfo;
端点remoteEnd =新IPEndPoint(IPAddress.Any,0);
的Socket标志= SocketFlags.None;
插座袜子=(插座)iar.AsyncState;

INT收到= sock.EndReceiveMessageFrom(IAR,楼盘旗帜,裁判remoteEnd,出packetInfo);
Console.WriteLine(
{0}从接收的字节{1}到{2},
收到
remoteEnd,
packetInfo.Address
);
}

请注意,你应该很明显叫 SetSocketOption(SocketOptionLevel。 IP,SocketOptionName.PacketInformation,真实)如设置插座的一部分的之前绑定的。该... ... ReceiveMessageFrom方法将其设置为你,但你可能只能看到在Windows上看到,选项设置之后的任何数据包的有效信息。 (实际上,这不是大问题 - 但是当/如果它曾经发生过,原因是一个谜更好的防止它完全。)


I have an asynchronous UDP server class with a socket bound on IPAddress.Any, and I'd like to know which IPAddress the received packet was sent to (...or received on). It seems that I can't just use the Socket.LocalEndPoint property, as it always returns 0.0.0.0 (which makes sense as it's bound to that...).

Here are the interesting parts of the code I'm currently using:

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.
}

As mentioned earlier this always prints a line like:

Received 32 bytes from 127.0.0.1:1678 to 0.0.0.0:12345

And I'd like it to be something like:

Received 32 bytes from 127.0.0.1:1678 to 127.0.0.1:12345

Thanks, in advance, for any ideas on this! --Adam

UPDATE

Well, I found a solution, though I don't like it... Basically, instead of opening a single udp socket bound to IPAddress.Any, I create a unique socket for every available IPAddress. So, the new Starter function looks like:

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);
    }
}

This is just to illustrate the concept, the biggest problem with this code as is, is that each socket is trying to use the same buffer... which is generally a bad idea...

There has to be a better solution to this; I mean, the source and destination are part of the UDP packet header! Oh well, I guess I'll go with this until there's something better.

解决方案

I just had the same problem. I don't see a way, using ReceiveFrom or its async variants, to retrieve the destination address of a received packet.

However...If you use ReceiveMessageFrom or its variants, you'll get an IPPacketInformation (by reference for ReceiveMessageFrom and EndReceiveMessageFrom, or as a property of the SocketAsyncEventArgs passed to your callback in ReceiveMessageFromAsync). That object will contain the IP address and interface number where the packet was received.

(Note, this code has not been tested, as i used ReceiveMessageFromAsync rather than the fakey-fake Begin/End calls.)

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
    );
}

Note, you should apparently call SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true) as part of setting up the socket, before you Bind it. The ...ReceiveMessageFrom... methods will set it for you, but you'll probably only see valid info on any packets Windows saw after the option was set. (In practice, this isn't much of an issue -- but when/if it ever happened, the reason would be a mystery. Better to prevent it altogether.)

这篇关于C#UDP套接字:获取接收器地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆