使用 UDP 发送到多个节点,同时保留相同的源端口

Sending to multiple nodes using UDP while retaining the same source port

是否有一种更简单或成本更低的方法能够从单个发送者向多个节点发送 UDP 数据报,而无需在 UdpClient 上调用 .Dispose() 然后重新发出 .Connect(string ip, int port)命令?

private UdpClient _UdpClient = new UdpClient(8000);

public void Send(string ip, int port, byte[] data)
{ 
    _UdpClient.Dispose();
    _UdpClient = new UdpClient(_Port);
    _UdpClient.Connect(ip, port);
    _UdpClient.Send(data, data.Length);
}           

我试过简单地调用 Send 方法中的第三行和第四行,即 .Connect(ip, port).Send(data, data.Length),而不处理和重新实例化 _UdpClient,因为文档(https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.udpclient.connect?view=netcore-3.1) 指出:

If you want to send datagrams to a different remote host, you must make another call to the Connect method or create another UdpClient without a default remote host.

我不能使用另一个 UdpClient,因为我只能将 UdpClient 的一个实例绑定到所需的源端口。如果我每次都尝试使用新的 UdpClient,我自然而然地会得到这个异常:

Unhandled exception. System.Net.Sockets.SocketException (10048): Only one usage of each socket address (protocol/network address/port) is normally permitted.
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at System.Net.Sockets.UdpClient..ctor(Int32 port, AddressFamily family)
   at System.Net.Sockets.UdpClient..ctor(Int32 port)

我上面的代码有效;我怀疑 .Dispose() 和重新实例化很重,我的意思是它是 UDP 而不是 TCP,但我只是 觉得脏 这样写代码

当我尝试只使用 .Connect(ip, port) 而不使用 .Dispose() 并重新实例化时,我得到了与文档相反的行为。它将数据报发送到前面.Connect(ip, port)中定义的ip, port(很奇怪)。

环境是 Windows10,.NET Core 3.1。

--- 用解决方案编辑 ---

private UdpClient _UdpClient = new UdpClient(8000);

public void Send(string ip, int port, byte[] data)
{ 
    IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ip), port);
    _UdpClient.Send(data, data.Length, ipe);
}           

不要使用 Connect()

UDP 本来就不是面向连接的协议。尽管如此,据我所知,UDP 套接字支持 Connect() 方法,只是为了方便。在简单的场景中,调用一次 Connect() 比每次调用都必须传递远程端点地址更简单,而且它还具有过滤入站流量的效果。这些可以在某些情况下使代码更简单。

但就您而言,这并没有让事情变得更简单。所以不要使用它。有 Send()Receive() 重载允许您为每个发送指定远程端点,并为每个接收获取远程端点。

如果你可以使用Socketclass,那class提供了SendTo()ReceiveFrom()方法来达到同样的目的。 UdpClient 只是 Socket 的薄包装,所以通常这是 easier/preferable 的方式。

只要您不调用 Connect(),您就不应该 运行 遇到您遇到的问题。