【问题标题】:C# Winforms UDPClient Exception: "Only one usage of each socket address is normally permitted."C# Winforms UDPClient 异常:“每个套接字地址通常只允许使用一次。”
【发布时间】:2017-07-14 17:02:06
【问题描述】:

我正在使用 C#/Winforms 开发一个通过 UDP 与另一个系统通信的 GUI。我为此使用了 DotNet 'UdpClient' 类。我为每个传输使用一个套接字,一个用于接收:

UdpClient client = new UdpClient(receiveport_num);
client.Client.SetSocketOption(SocketOptionLevel.Socket,     SocketOptionName.ReuseAddress, true);
client.Client.SetSocketOption(SocketOptionLevel.Socket,     SocketOptionName.ExclusiveAddressUse, false);
client.BeginReceive(DataReceived, client);

UdpClient server = new UdpClient(ConnectionSettings.soport);
server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, false);

然后使用 server.Send 从“服务器”套接字接收。

一旦我完成了套接字,或者应用程序关闭,它们就会被处理掉:

client.Client.Shutdown(SocketShutdown.Both);
client.Client.Close();
client.Close();
client = null;

server.Client.Shutdown(SocketShutdown.Both);
server.Client.Close();
server.Close();
server = null;

由于某种原因,如果我尝试重新创建这些套接字,无论是通过再次创建套接字还是重新启动应用程序,都会出现异常:

System: Only one usage of each socket address (protocol/network) is normally permitted.

我理解这是因为即使我关闭了套接字,底层的 Windows 套接字仍在徘徊,因为 Windows 使它们保持活动状态......

我想每次都使用相同的端口号并重新创建套接字。我怎样才能做到这一点?如果这是不可能的(如果你问我,这在 Windows 中听起来有点像网络问题......),那么有没有办法让我重新获取套接字以供我使用?

【问题讨论】:

  • 如果没有一个好的minimal reproducible example 可以可靠地重现问题,就不可能确定问题出在哪里。但请放心,您无需致电SetSocketOption() 即可让工作正常进行。另请注意,您不应在 UDP 套接字上调用 Shutdown()。这是面向连接的套接字。我没有测试过自己,但可能是 Shutdown() 导致了延迟状态并导致错误消息。
  • "我使用一个套接字用于每次传输,一个用于接收:" -- 这对于测试目的来说很好,即将两个端点放在同一个程序中.但否则,不要。一个套接字既可以接收也可以发送。如果你想在同一个程序中,甚至在同一台计算机上有两个端点,这些端点需要使用不同的端口号。不要尝试在同一台计算机上使用相同的端口号创建多个套接字。
  • 我会尝试删除 Shutdown(),但是查看不应该引起问题的 MDSN 文档......我应该更具体地了解套接字:这是两个不同的套接字,使用两个不同的端口。一个是从端口 X 接收,另一个是在端口 Y 上发送。整个 SetSocketOption 之前不存在,这只是我试图让套接字正确释放自身的尝试。我在其他操作系统中使用了完全相同的架构而没有问题,所以这似乎是 Windows 处理这些事情的方式的更多问题......

标签: c# .net windows sockets networking


【解决方案1】:

我发现了问题。我的应用程序使用Process.Start(ProcessStartInfo pi) 生成进程。使用该函数时,属于主应用进程的所有句柄(包括套接字)都被子进程继承。

当父进程死亡时,子进程仍然处于活动状态,保持套接字打开。这可以通过以下两种方式之一解决:

a) 使用 P/Invoke,将 Process.Start 替换为 createprocess(),将 bInheritHandles 设置为 false。据我所知,dotNet Process.Start 函数没有任何等效项,在我看来这是一个疏忽。

b) 使用 P/Invoke,在创建您不希望子进程继承的每个套接字后,使用 INHERIT 作为 dwMask 参数调用 SetHandleInformation(),并将 NONE 作为 dwFlags 参数调用.

【讨论】:

    猜你喜欢
    • 2014-01-16
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    相关资源
    最近更新 更多