本文主要針對MFC庫中的CAsyncSocket類和CSocket類,才疏學淺,權當做拋磚引玉。
這裡所列出的問題主要是在最近編寫基於IP網的語音交談程式的過程中碰到的,不一定很
具代表性,僅供參考和討論。對於從事Win32平台的VOIP開發工作的朋友們,或許會有點利
用價值。
1. CSocket類和CAsyncSocket類對多線程的支援問題
Winsocks本身是支援多線程的,具有一定的線程獨立性和安全性,但CSocket類以及CAsyn
cSocket類都有一些執行緒安全性問題。比如線上程之間傳遞CSocket對象就會發生異常,MS
DN中的建議是,傳遞前Detach,傳遞socket控制代碼,在目標線程中再Attach到一個CSocket對
象上。這似乎說明CSocket(或CAsyncSocket)具有線程依賴性。
然而情況並不是絕對的,我的程式中出現的兩種傳遞CAsyncSocket或CSocket對象的情況沒
有發生異常,也沒有運行效率的問題:
(1) 在主線程中建立和關閉一個CSocket阻塞型資料通訊端,在另一線程中用它發送資料
(SendTo)。若用它接收資料(ReceiveFrom)則出現異常。
(2) 在主線程中建立和關閉一個CAsyncSocket非阻塞型資料通訊端,在另一線程中用它
接收資料(ReceiveFrom)也沒有問題了。
上述兩種情況,我的感覺是毫無道理可言,但在我的機器上運行卻是非常穩定。我的建議
是,如果使用CAsyncSocket類和CSocket類,盡量不要跨線程使用(我以後也不會鋌而走險
了)。
2. 阻塞和非阻塞的選擇問題
阻塞通訊端使用方便,但會影響到線程的訊息響應,比較適合於用流式通訊端傳送大量數
據的情況。
對於即時語音資料的傳送來說,資料的發送受制於音頻採集裝置,一旦有資料可發送,才
調用通訊端來發送,因而通訊端的阻塞與否對線程的已耗用時間佔用不會太大(我的程式中
一個資料包的大小隻有20KB,發送的過程很快)。而在接收方,音頻回放裝置受制於接收
通訊端。在沒有接受到任何資料時,整個線程卻卡在ReceiveForm()上,無法實現正常的消
息迴圈,如此時向該線程發出WM_QUIT訊息,它將無法得到執行。同樣,在發送方,為了不
阻塞發送線程的訊息迴圈,音頻採集裝置也應該是非阻塞(非同步)的。
當然,如果不將音頻回放和資料接收放在同一線程中,則也可以用阻塞型通訊端,但是這
又帶來另一個問題:兩個線程間要共用資料,於是又要涉及到線程間同步或互斥的問題,
同時增加了系統開銷。
3、將通訊端事件映射到視窗訊息上時應注意:
當用WSAAsyncSelect將通訊端事件映射到視窗訊息上時,應注意視窗的訊息阻塞可能會造
成通訊端錯誤,如公用對話方塊。特別是在用PreTranslateMessage時極可能出問題。
4、再說兩句廢話。MFC支援Windows Sockets1但不支援Windows Sockets2。因而一些優良
的效能將不能使用,如服務品質(QoS)、有根多播。而在某些功能,如IP網多播的使用上
,Windows Sockets1和Windows Sockets2是有一些區別的