2017-02-24 32 views
-1

我正在使用C#/ Winforms通过UDP与另一个系统进行通信。我正在使用DotNet的'UdpClient'类。我使用每个发射一个插座,以及一个用于接收:C#Winforms 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中的一个网络问题),那么是否有一种方法可以重新获取我使用的套接字?

+0

没有一个可靠地再现问题的好的[mcve],就不可能知道什么是错的。但请放心,您不需要调用'SetSocketOption()'来让事情顺利进行。还要注意,你不应该在UDP套接字上调用'Shutdown()'。这是面向连接的套接字。我没有测试过自己,但可能是'Shutdown()'导致延迟状态并导致错误消息。 –

+0

_“我为每个传输使用一个套接字,一个用于接收:”_ - 这对测试目的而言是很好的,即将两个端点放在同一个程序中。但否则,不要。一个套接字可以接收和发送。如果你想在同一个程序中使用两个端点,或者甚至在同一台计算机上,那么这些端点需要使用不同的端口号。不要试图在具有相同端口#的同一台计算机上制作多个套接字。 –

+0

我会尝试删除'Shutdown()',但是查看不应该导致问题的MDSN文档...我应该更具体地介绍套接字:这是两个不同的套接字,使用两个不同的端口。一个是从端口X接收,另一个是在端口Y发送。整个'SetSocketOption'事情都没有在那里,这只是我试图让套接字正确释放自己。我在其他操作系统中使用了完全相同的体系结构,没有出现问题,所以这似乎更像是Windows处理这些事情的一个问题。 –

回答

0

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

父进程终止时,该子仍处于活动状态,保持套接字处于打开状态。这可以通过两种方式解决:

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

b)使用的P/Invoke,创建每个插座后,你不希望子进程继承,调用SetHandleInformation()INHERIT作为dwMask参数,NONE作为dwFlags参数。

相关问题