2017-03-14 132 views
0

使用System.Net.WebSockets.WebSocket我在一個線程中有一個讀循環。關閉WebSocket Threadsafe

var result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); 

從我寫的另一個線程。

lock (ws) 
    ws.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None).Wait(); 

這工作正常。

我的問題是,我該如何幹淨地關閉這個連接?

任何試圖在一個異常關閉的結果:

await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Bye", CancellationToken.None); 
InvalidOperationException: 'Concurrent reads are not supported.' 

我試圖傳遞一個CancellationTokenws.ReceiveAsync,這樣我可以從接收循環中調用ws.CloseAsync。這並沒有中斷ReceiveAsync呼叫,它在下一條消息到達時返回。

是否可以乾淨地關閉讀取循環外的套接字。 我可以實現「關閉連接」消息,但在WebSocket協議中存在發送關閉消息的概念時似乎過度消耗。

+0

你確定* CancellationToken不會取消ReceiveAsync嗎?這似乎很奇怪。 –

+0

@StephenCleary至少不會在下一條消息到達之前5-10秒之後 – hultqvist

+1

在這種情況下,您需要調用CloseOutputAsync並在讀取中處理CloseSent消息類型。 –

回答

0

在這種情況下,你需要調用CloseOutputAsync和處理 CloseSent消息鍵入您的閱讀。 - Stephen Cleary 3月14日13:49

當另一個線程正在等待ReceiveAsync時,您可以撥打CloseOutputAsync

1

在此代碼中看不到併發讀取 - 如果您僅從單個線程調用ReceiveAsync,並且在開始下一個之前等待操作的結果,則不應該有此例外。它在哪裏拋出?

對寫作部分的建議:如果使用鎖定和阻止寫入(使用.Wait()),則會阻塞完整線程(可能運行其他句柄),這可能不是您想要的。更好地利用SemaphoreSlim相反,在這裏你可以這樣做:

await semaphore.WaitAsync(); 
try 
{ 
    await ws.SendAsync(); 
} 
finally 
{ 
    semaphore.Release(); 
} 

如果錯誤消息的文本是不準確的,它實際上抱怨併發SendClose,那麼你可以使用同樣的信號也爲保護Close通話:

await semaphore.WaitAsync(); 
try 
{ 
    await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Bye", CancellationToken.None); 
} 
finally 
{ 
    semaphore.Release(); 
} 
+0

'CloseAsync'調用引發異常。 – hultqvist