我已經使用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