2010-06-11 93 views
1

我有一臺服務器有幾個客戶端C1 ... Cn,每個客戶端都建立了一個TCP連接。有不到10,000個客戶。順序訪問異步套接字

消息協議是基於請求/響應的,服務器向客戶端發送請求,然後客戶端發送響應。

服務器有幾個線程T1 ... Tm,並且每個線程都可以向任何客戶端發送請求。我想確保只有其中一個線程可以在任何時候向特定客戶端發送請求,而其他線程想要向同一客戶端發送請求將不得不等待。

我不想阻止線程同時向不同的客戶端發送請求。

E.g.如果T1向C3發送一個請求,另一個線程T2應該不能向C3發送任何東西,直到T1收到它的響應。

我想用插座上一個簡單的鎖聲明:

lock (c3Socket) 
{ 
    // Send request to C3 
    // Get response from C3 
} 

我使用異步插座,所以我可能要使用監視器來代替:

Monitor.Enter(c3Socket); // Before calling .BeginReceive() 

而且

Monitor.Exit(c3Socket); // In .EndReceive 

我很擔心東西出了問題,不放開顯示器,因此阻止所有acc給客戶。我在想,我的心跳線程可能會使用Monitor.TryEnter()超時並拋出無法獲取顯示器的套接字。

爲了能夠使用lock()語句,使Begin和End調用同步是否合理?我知道在這種情況下我會犧牲併發性,但這可能是值得的。

我可以在這裏忽略任何東西嗎?任何輸入讚賞。

回答

2

我的答案在這裏是一個狀態機每個插座。該州將freebusy

  • 如果插座是free,發件人線程將標誌着它busy並開始發送給客戶端,並等待迴應。
  • 您可能需要設置一個超時時間,以防止客戶端卡住。
  • 如果狀態爲busy - 線程正在休眠,正在等待信號。
  • 當與客戶端有關的超時過期時 - 關閉套接字,客戶端已經死亡。
  • 成功接收/解析響應時,再次標記套接字free併發信號/喚醒等待的線程。
  • 只鎖定socket狀態查詢和操縱,而不是實際的網絡IO。這意味着每個套接字的鎖,加上某種等待原語,如條件變量(對不起,不記得.NET中真正可用的)

希望這有助於。

+0

我將套接字封裝在一個對象中(我稱之爲SocketHolder),所以這看起來像是一個顯而易見的地方,將忙/閒狀態。感謝這個想法。 – 2010-06-11 20:12:37

2

您當然不能使用您描述的鎖定方法。由於你的系統主要是異步的,你無法知道將要運行什麼線程操作。這意味着你可以在錯誤的線程上調用Exit(並拋出SynchronizationLockException),或者其他一些線程可能會調用Enter並且即使該客戶端「正在使用」也會成功,僅僅是因爲它碰巧得到了與Enter一樣的線程最初呼籲。

我同意尼古拉的看法,您需要在每個插槽旁邊保留一些額外的狀態以確定它是否正在使用中。你當然需要鎖定來更新這個共享狀態。

+0

所以你是說EndReceive返回的線程與BeginSend的線程不同?我甚至沒有想到,但這是一個很好的觀點。 – 2010-06-11 19:54:18

+0

它肯定可以回到不同的線程,你唯一的選擇是以某種方式將回調編組回到名爲BeginSend的線程上。要做到這一點當然意味着讓BeginSend線程掛起,在這一點上,你已經失去了異步點:) – 2010-06-11 20:05:31

+0

絕對看起來像是一個好主意,將它與套接字一起存儲。謝謝! – 2010-06-11 20:14:24