WFMO_Reactor的與眾不同

字號:

WFMO_Reactor是ACE_Reactor在Windows下的默認(rèn)實現(xiàn)(為什么不選擇ACE_Select_Reactor作為默認(rèn)實現(xiàn),可能是基于效率和強大性的考慮),WFMO_Reactor的低層使用的函數(shù)是WaitForMultipleObjects和WSAEventSelect,WSAEnumNetworkEvents。其中WaitForMultipleObjects函數(shù)用于處理線程,互斥量,信號燈,事件,定時器等事件,而WSAEventSelect用于處理網(wǎng)絡(luò)IO事件。
    由于Windows API和操作系統(tǒng)的特性不一樣,WFMO_Reactor在很多地方的表現(xiàn)和其他平臺不一致。
    【注】其實這兩個問題在《C++ Network Programming Volume 2 - Systematic Reuse with ACE and Frameworks》中4.4 The ACE_WFMO_Reactor Class有說明??荚嚧缶庉嬚?,希望以地各位有所幫助。
    1 WFMO_Reactor只能處理62個句柄
    由于WaitForMultipleObjects不是一個處理大量事件的函數(shù),其最多處理64個事件句柄,而WFMO_Reactor自身為了處理使用了2個句柄,所以一個WFMO_Rector對象只能處理。
    如果你想做大規(guī)模的網(wǎng)絡(luò)接入,62個事件句柄顯然是不夠的,特別是要同時處理IO事件時,導(dǎo)致這個不足的應(yīng)該是WFMO_Reactor的設(shè)計者的一個選擇。在賦予WFMO_Reactor強大的特性的同時,WFMO_Reactor的設(shè)計者只能讓網(wǎng)絡(luò)IO事件的數(shù)量委屈一下了。
    2 WRITE_MASK觸發(fā)機制
    WFMO_Reactor 選擇的是Windows的WSAEventSelect 函數(shù)作為網(wǎng)絡(luò)的IO的反應(yīng)器。但是WSAEventSelect函數(shù)的FD_WRITE的事件處理和傳統(tǒng)的IO反應(yīng)器(select)不同。下面是MSDN的描述。
    The FD_WRITE network event is handled slightly differently. An FD_WRITE network event is recorded when a socket is first connected with connect/WSAConnect or accepted with accept/WSAAccept, and then after a send fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore, an application can assume that sends are possible starting from the first FD_WRITE network event setting and lasting until a send returns WSAEWOULDBLOCK. After such a failure, the application will find out that sends are again possible when an FD_WRITE network event is recorded and the associated event object is set.
    簡單翻譯就是,只有在三種條件下,WSAEventSelect才會發(fā)出FD_WRITE通知,一是使用connect或WSAConnect,一個套接字成功建立連接后;二是使用accept或WSAAccept,套接字被接受以后;三是若send、WSASend、sendto或WSASendTo函數(shù)返回失敗,而且錯誤是WSAEWOULDBLOCK錯誤后,緩沖區(qū)的空間再次變得可用時?!咀ⅰ?BR>    【注】這種觸發(fā)方式在IO反應(yīng)器或者說IO多路復(fù)用模型中應(yīng)該被稱為邊緣觸發(fā)方式。select函數(shù)好像沒有這種觸發(fā)方式而是水平觸發(fā)方式, Epoll是支持這種方式的,但是默認(rèn)還是水平觸發(fā),這種方式可能有更高的效率,但是代碼更加難寫。
    可以這么理解,WSAEventSelect認(rèn)為套接字基本都是可寫狀態(tài),它認(rèn)為你應(yīng)該大膽send。只有send出現(xiàn)WSAEWOULDBLOCK失敗后,你才需要使用WSAEventSelect反應(yīng)器。
    所以對于WFMO_Reactor的,你不可能依靠注冊(或者是喚醒)IO句柄進(jìn)行寫操作,WMFO_Reactor很有可能不會去回調(diào)你的handle_output函數(shù)。
    【注】對于網(wǎng)絡(luò)套接字,只要緩沖區(qū)還有空間就可以直接發(fā)送,除非緩沖區(qū)沒有空間了,才可能出現(xiàn)阻塞錯誤,所以直接send失敗的可能性很小,另外反復(fù)調(diào)用注冊IO句柄一類的操作其實是比較耗時的。其實先send,如果send失敗再注冊IO句柄到反應(yīng)器的方式應(yīng)該是一種更加高效的方式,高壓力的通訊服務(wù)器應(yīng)該選擇這個編寫方式。
    通信服務(wù)器通過這個改造,提高的性能在15%左右(CPU占用率下降)。
    由于WFMO_Reactor的這些特點,其實很大的限制了Reactor的可移植性。其實個人感覺如果你對系統(tǒng)特性沒有那么多要求,在Windows下選擇Select_Reactor替換WFMO_Reactor是更好的選擇。