【发布时间】:2011-05-18 13:54:45
【问题描述】:
我使用MSDN 和(大部分)CodeProject 中的示例来编写套接字服务器。我试图了解代码的线程安全性。所有套接字事件都会触发 IO_Completed 方法,该方法检查 SAEA 的最后操作类型(发送或接收):
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 服务),再次运行相同代码的机会一定非常高。
在不影响使用 SocketAsyncEventArgs 获得的性能的情况下,我需要做什么才能使 ProcessReceive()(和其他相关方法)通常是线程安全的?
以下示例 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);
}
}
【问题讨论】:
标签: c# sockets thread-safety