【发布时间】:2016-01-11 21:42:47
【问题描述】:
我有一个使用UdpClient、TcpClient、TcpListener 的多线程网络应用程序,并使用例如处理接收到的连接和接收到的数据。 BeginReceive() EndReceive() 回调模式。
以 UdpClient 为例,在这个模式中,我使用的一般工作流程是:
- 致电
UdpClient.BeginReceive() - 接收到数据报时执行接收回调。
- 致电
UdpClient.EndReceive()收集数据报。 - 再次调用
UdpClient.BeginReceive(),准备接收另一个数据报。 - 处理在 (3) 处收到的数据报。
- 收到更多数据报时重复 2 - 5
问:由于只有一个UdpClient 对象,并且由于总是在下一个BeginReceive() 之前调用EndReceive() 的模式,是否有必要锁定/同步访问那些调用的UdpClient 对象?
在我看来,其他线程不可能干预此工作流程或使这些调用成为非原子调用。 TcpClient.BeginReceive() 和 TcpListener.BeginAcceptTcpClient() 的模式非常相似。
额外问题:是否需要声明单个UdpClient 对象static(如果需要,static 锁定object)?
注意:我不询问是否有必要在例如数据报处理。仅关于此模式和 UdpClient TcpClient TcpListener 对象。
编辑
澄清一下,(忽略异常处理)是这段代码:
private void InitUDP()
{
udpclient = new UdpClient(new IPEndPoint(IPAddress.Any, Settings.Port));
udpclient.BeginReceive(new AsyncCallback(receiveCallback), udpclient);
}
private void receiveCallback(IAsyncResult ar)
{
UdpClient client = (UdpClient)ar.AsyncState;
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
byte[] datagram = client.EndReceive(ar, ref ep);
udpclient.BeginReceive(new AsyncCallback(receiveCallback), udpclient);
processDatagram();
}
实际上与此代码不同或保护性较低:
private void InitUDP()
{
udpclient = new UdpClient(new IPEndPoint(IPAddress.Any, Settings.Port));
udpclient.BeginReceive(new AsyncCallback(receiveCallback), udpclient);
}
private void receiveCallback(IAsyncResult ar)
{
UdpClient client = (UdpClient)ar.AsyncState;
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
lock(_lock)
{
byte[] datagram = client.EndReceive(ar, ref ep);
udpclient.BeginReceive(new AsyncCallback(receiveCallback), udpclient);
}
processDatagram();
}
【问题讨论】:
-
UdpClient成员函数不是线程安全的,所以如果多个线程访问同一个实例,那么您就有问题了。我不确定这是否是您的问题。 -
这就是问题所在 - 如果总是在下一个
BeginReceive()之前调用EndReceive(),那么另一个线程是否可以通过这些回调访问同一个实例?我需要锁定这些电话吗? -
你是线程的控制者,所以你决定哪个线程访问什么。那么有可能吗?是的,如果回调可以合法地访问实例,例如当它是公共的或回调是同一实例的成员时 - 在某种程度上,如果您可以编写代码来访问回调中的实例并且它编译然后,是的,您可以访问它。但除非我误解了,否则这不是你真正想要回答的问题,因为就像我说的,你决定每个回调/线程做什么,对吧?
-
这是另一个 SO 答案,展示了如何use
BeginReceiveandEndReceive。它还谈到了使用任务作为简化代码的一种方式,这也清楚地表明你的代码/回调中没有线程。
标签: c# multithreading sockets tcpclient udpclient