Windows下完成端口移植Linux下的epoll
生活随笔
收集整理的這篇文章主要介紹了
Windows下完成端口移植Linux下的epoll
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
??? ?距離上一篇博客都已經半個多月了,這么多天一直在學習研究關于Windows的完成端口移植到Linux下epoll方面的內容。這兩方面以前都沒有太多的接觸,所以花費了較長的時間。在連續加班兩天后,用一個周末的代價換來了一個調試成功。下面就把最近的成果與各位網友分享一下。如有不正確之處,望指正。 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
hIocp = CreateIoCompletionPort(
????????INVALID_HANDLE_VALUE,
????????NULL,
????????(ULONG_PTR)0,
????????0);
if (hIocp == NULL) {
????????// Error
} ???完成端口創建后,要把將使用該完成端口的套接字與之關聯起來。方法是再次調用CreateIoCompletionPort ()函數,第一個參數FileHandle設為套接字的句柄,第二個參數ExistingCompletionPort 設為剛剛創建的那個完成端口的句柄。
以下代碼創建了一個套接字,并把它和前面創建的完成端口關聯起來: SOCKET????????s;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
????????// Error }
if (CreateIoCompletionPort((HANDLE)s,?
?????????????????????????????????????? hIocp,?
??????????????????????????????????????(ULONG_PTR)0,?
?????????????????????????????????????????????????????? ?0) == NULL)
{
// Error
}
... 這時就完成了套接字與完成端口的關聯操作。在這個套接字上進行的任何重疊操作都將通過完成端口發出完成通知。
????????HANDLE CompletionPort,?????????????// handle to completion port
????????LPDWORD lpNumberOfBytes,????????// bytes transferred
????????PULONG_PTR lpCompletionKey,???? // file completion key
????????LPOVERLAPPED *lpOverlapped,???? // buffer
????????DWORD dwMilliseconds???????????? // optional timeout value
);
DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd,
LPINT lpFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE
l???? pCompletionRoutine );? lpOverlapped:一個指向WSAOVERLAPPED結構的指針,在這個參數中就可以設置你要接收的數據結構。
SOCKET s,????
LPWSABUF lpBuffers,
DWORD dwBufferCount,????
LPDWORD lpNumberOfBytesSent,
int iFlags,????
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);? 同理,lpOverlapped用來設置發送是數據結構。
?
?先來說說Windows下的完成端口。完成端口號稱是Windows下面最復雜的異步IO操作。但是如果你想開發出具有高性能的、支持大量連接的網絡服務程序的話,就必須將它拿下。這里假設你已經對完成端口有一定的了解了。?
??? ?下面引用一下幽默講解Windows支持的五種Socket I/O模型的例子來通俗的說一下完成端口究竟是怎么回事。 ?? ?老陳有一個在外地工作的女兒,不能經常回來,老陳和她通過信件聯系。他們的信會被郵遞員投遞到他們的微軟信箱里。 ??? ?我們平時使用的select模型,老陳每隔幾分鐘便到樓下看看是否有信。這樣的方式會浪費老陳很多時間。同理,程序會阻塞在這里等待數據的到來,使得該進程(線程)無法進行其他的操作,導致性能的降低。 ??? ?WSAAsyncSelect模型、WSAEventSelect模型同為事件觸發模型。此時,只要有信到,微軟就會主動通知老陳。此時,老陳只需要等待通知即可,在等待過程中可以做其他的事情。 ?而Overlapped I/O 事件通知模型基本和上面兩種類似。只是,老陳不需要上下樓取信了,他只需告訴微軟自己在幾樓幾號,微軟就會把信送到老陳家里。 ??? ?后來微軟推出了Overlapped I/O 完成例程模型,老陳將自己拆信—閱讀—回復的過程告訴微軟,微軟就會按照上述步驟去處理信件。 ??? ?但是,由于微軟要處理的信件實在太多了,信箱經常崩潰。于是采用了新技術Completion Port來處理這些信件。?
??? ?通過Win32的重疊I/O機制,應用程序可以提請一項I/O操作,重疊的操作請求在后臺完成,而同一時間提請操作的線程去做其他的事情。等重疊操作完成后線程收到有關的通知。而一個完成端口其實就是一個通知隊列,由操作系統把已經完成的重疊I/O請求的通知放入其中。當某項I/O操作一旦完成,某個可以對該操作結果進行處理的工作者線程就會收到一則通知。?
??? ?完成端口的使用主要分兩步。 ??? ?首先,創建完成端口 HANDLE????????hIocp;hIocp = CreateIoCompletionPort(
????????INVALID_HANDLE_VALUE,
????????NULL,
????????(ULONG_PTR)0,
????????0);
if (hIocp == NULL) {
????????// Error
} ???完成端口創建后,要把將使用該完成端口的套接字與之關聯起來。方法是再次調用CreateIoCompletionPort ()函數,第一個參數FileHandle設為套接字的句柄,第二個參數ExistingCompletionPort 設為剛剛創建的那個完成端口的句柄。
以下代碼創建了一個套接字,并把它和前面創建的完成端口關聯起來: SOCKET????????s;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
????????// Error }
if (CreateIoCompletionPort((HANDLE)s,?
?????????????????????????????????????? hIocp,?
??????????????????????????????????????(ULONG_PTR)0,?
?????????????????????????????????????????????????????? ?0) == NULL)
{
// Error
}
... 這時就完成了套接字與完成端口的關聯操作。在這個套接字上進行的任何重疊操作都將通過完成端口發出完成通知。
?
??? 其次,使用API函數GetQueuedCompletionStatus來不斷的監聽查詢某個完成端口的I/O操作的結果。通常來講,在主線程中都只創建一個完成端口,將所有的套接字都與此完成端口關聯。而進行監聽查詢的線程數一般取CPU數量的兩倍。 BOOL GetQueuedCompletionStatus(????????HANDLE CompletionPort,?????????????// handle to completion port
????????LPDWORD lpNumberOfBytes,????????// bytes transferred
????????PULONG_PTR lpCompletionKey,???? // file completion key
????????LPOVERLAPPED *lpOverlapped,???? // buffer
????????DWORD dwMilliseconds???????????? // optional timeout value
);
?
第一個參數指出了線程要監視哪一個完成端口。GetQueuedCompletionStatus使調用線程掛起,直到指定的端口的I/O完成隊列中出現了一項或直到超時。同I/O完成端口相關聯的第3個數據結構是使線程得到完成I/O項中的信息:傳輸的字節數,完成鍵和OVERLAPPED結構的地址。該信息是通過傳遞給GetQueuedCompletionSatatus的lpdwNumberOfBytesTransferred,lpdwCompletionKey和lpOverlapped參數返回給線程的。 ??? ?注意lpOverlapped,這是很重要的一個數據結構,從這里你將獲得你想要的數據,并進行判斷處理。這里你可能會問,這個lpOverlapped數據結構是哪里來的,是什么類型的呢?接下來你就明白了。?
??? 上面討論了完成端口的使用,這其實是后期的處理,要想真正了解整個過程,還需要學習下面關于之前如何將發送和接收數據的I/O操作提交。 ??? 一個是API函數WSARecv從一個套接口接收數據。int WSAAPI WSARecv ( SOCKET s, LPWSABUF lpBuffers,
DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd,
LPINT lpFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE
l???? pCompletionRoutine );? lpOverlapped:一個指向WSAOVERLAPPED結構的指針,在這個參數中就可以設置你要接收的數據結構。
?
另一個是API函數WASSend在一個已連接的套接口上發送數據。int WSAAPI WSASend (????
SOCKET s,????
LPWSABUF lpBuffers,
DWORD dwBufferCount,????
LPDWORD lpNumberOfBytesSent,
int iFlags,????
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);? 同理,lpOverlapped用來設置發送是數據結構。
?
對完成端口來說,將一個套結字邦定到完成端口后,WSARecv和WSASend會立即返回,提高了系統的效率。可以調用 GetQueuedCompletionStatus來判斷WSARecv和WSASend是否完成。主線程接受到一個連接后,調用WSARecv等待該連接發送的數據(不阻塞,由完成端口實現數據的接受完畢判斷)。在線程函數中接受完畢,然后用WSASend函數發送給客戶數據(同樣是不阻塞,直接返回,由完成端口判斷數據是否發送完畢)。這樣在線程函數中需要程序員自己設置狀態來區分是發送完畢還是接受完畢。 注意WSARecv 只是向系統提交一個異步接收請求,這個請求會在有數據到達之后返回,并且放入完成隊列通知工作線程,這個異步接收請求到此完成,繼續提交請求是為了接收下一個數據包,也就是說,每次請求返回之后必須再次提交。WSASend也只是向系統提交一個異步發送請求,當發送成功后,需要提交WSARecv接收請求,因為發送是主動的,發送完畢后必然要等待接收對方的回復。如果不提交WSARecv接收請求,則對方發過來的數據后,完成端口不會監聽。?
先寫這些,下一篇在寫關于Linux下面epoll的相關內容。轉載于:https://blog.51cto.com/jazka/251759
總結
以上是生活随笔為你收集整理的Windows下完成端口移植Linux下的epoll的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win2003安装后的十个小技巧
- 下一篇: linux 其他常用命令