我已经使用MSDN和(大部分)CodeProject中的示例编写套接字服务器。我试图让我的头脑围绕代码的线程安全性。所有的套接字事件触发IO_Completed方法来检查该SAEA上一操作类型(发送或接收):SocketAsyncEventArgs和.Net中的线程安全
void IO_Completed(object sender, SocketAsyncEventArgs e)
{
// determine which type of operation just completed and call the associated handler
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
思考来电,确实ProcessReceive()需要完全线程安全的,因为它可以被称为多如果有很多客户端,或者在某种程度上阻塞了它,以便在下一个事件再次调用它之前完全完成?我所做的不仅仅是将收到的消息直接反弹回客户端(这正是示例所做的)。
即使在这些例子中,ProcessReceive()也是一个相当长的方法(见下文),并且肯定必须处于第二个线程的破坏风险之中。当我添加代码时,我需要做些明智的事情(调用WCF服务),再次运行相同代码的机会必须非常高。
我需要做什么才能使ProcessReceive()(和其他相关方法)通常是线程安全的,而不会影响使用SocketAsyncEventArgs获得的性能?
实施例ProcessReceive()以下方法:
private void ProcessReceive(SocketAsyncEventArgs receiveSendEventArgs)
{
DataHoldingUserToken receiveSendToken =
(DataHoldingUserToken)receiveSendEventArgs.UserToken;
if (receiveSendEventArgs.SocketError != SocketError.Success)
{
receiveSendToken.Reset();
CloseClientSocket(receiveSendEventArgs);
return;
}
if (receiveSendEventArgs.BytesTransferred == 0)
{
receiveSendToken.Reset();
CloseClientSocket(receiveSendEventArgs);
return;
}
Int32 remainingBytesToProcess = receiveSendEventArgs.BytesTransferred;
if (receiveSendToken.receivedPrefixBytesDoneCount <
this.socketListenerSettings.ReceivePrefixLength)
{
remainingBytesToProcess = prefixHandler.HandlePrefix(receiveSendEventArgs,
receiveSendToken, remainingBytesToProcess);
if (remainingBytesToProcess == 0)
{
StartReceive(receiveSendEventArgs);
return;
}
}
bool incomingTcpMessageIsReady = messageHandler
.HandleMessage(receiveSendEventArgs,
receiveSendToken, remainingBytesToProcess);
if (incomingTcpMessageIsReady == true)
{
receiveSendToken.theMediator.HandleData(receiveSendToken.theDataHolder);
receiveSendToken.CreateNewDataHolder();
receiveSendToken.Reset();
receiveSendToken.theMediator.PrepareOutgoingData();
StartSend(receiveSendToken.theMediator.GiveBack());
}
else
{
receiveSendToken.receiveMessageOffset = receiveSendToken.bufferOffsetReceive;
receiveSendToken.recPrefixBytesDoneThisOp = 0;
StartReceive(receiveSendEventArgs);
}
}
谢谢,这有助于清除雾! – Alan 2011-05-18 11:36:55
你能否提供一个资源,专门说明Completed事件是在ThreadPool的线程上完成的? – nietras 2013-07-02 20:01:01
@harrydev:我找不到一个,但SAEA基本上是做'Begin' /'End'的一种不同方式,它在一个线程池线程上调用它的回调函数。 – 2013-07-02 20:21:40