1 Windows完成端口基本介紹
2他是只能在Windows下的基于SOCKET事件管理的模型
3與select不同,select需要多次重置管理句柄,IOCP只要一次
4有事件后select需要操作獲取數據,而IOCP通知你的時候說明數據操作好了
5select管理句柄的數目有限,IOCP沒有限制
6IOCP支持多線程同時等待。
我的設計思路一個線程用來偵聽accept事件, 一個線程來偵聽SOCKET的IO事件,
大部分框架都是這樣, 其實可以只使用一個線程做異步SOCKET就完全足夠了,現在
使用多線程來 就是看看這個IOCP的多線程用法,
在這之前先要了解下 異步通信 和 重疊I/O模型
異步通信機制: https://blog.51cto.com/blogger/draft/412685
重疊I/O模型: https://blog.51cto.com/12158490/2058180
我建議使用單線程 原因: 應為多個線程,拿到數據后,還是要發送到另外一個線程里面去,
然后做成事件隊列, 也就是你線程拿到數據后, 還是要按隊列線程,進行邏輯處理,多線程沒意義。
2完成端口內部運行流程
完成端口的做法:事先開好幾個線程,你有幾個CPU我就開幾個,首先是避免了線程的上下文切換,因為線程想要
執行的時候,總有CPU資源可用,然后讓幾個線程等著,等到有用戶請求到來的時候,就把這些請求都加入到一個
公共消息隊列中, 然后這幾個開好的線程就排隊逐一去從消息隊列中取出消息并加以處理, 這種方式實現了
異步通信和負載均衡的問題,因為他提供了一種機制來使用幾個線程"公平的"處理來自多個客戶端的輸入/輸出
,并且線程如果沒事干的時候,也會被系統掛起,不會占用CPU。
3WSAAsyncSelect或者WSAEventSelect和完成端口
WSAAsyncSelect或者WSAEventSelect兩種異步模型, 這兩種模式一定沒有使用overlapped(重疊)機制,
就不能算是真正的異步,可能是其內部維護了一個消息隊列,這兩個模式雖然實現了異步接收,卻不能異步的發送,
完成端口他是先把用戶數據接收回來后在通知用戶直接來取,而這兩種模式只會接到數據到達的通知,只能是由
應用程序自己去recv數據,性能上就發送了差異
要實現異步通信, 就要一個很強的I/O數據結構,叫重接結構"Overtlapped",
Window所有異步通信都是基于他,完成端口也不例外
就是執行I/O請求的時間與線程執行其他任務的事件是重疊(overlapped)的,
重疊結構是異步通信機制實現的一個核心數據結構,因為幾乎所有的網絡操作例如發送/接收,都要用
WSASend()和WSARecv()代替,參數里面都會要附帶一個重疊結構,因為重疊機構可以理解為是一個
網絡操作的ID號,也就是說我們要利用重疊I/O提供的異步機制的話,每一個網絡操作都要有一個唯一的ID號,
因為進來系統內核,一看到有重疊的I/O的調用進來了,就會使用其異步機制,并且操作系統就只能靠
這個重疊結構帶有的ID號來區分是哪一個網絡操作了,然后內核里處理完畢, 根據這個ID號,把對應的數據傳上去.
4完成端口基本的使用流程
完成端口也分步驟的
1調用CreateIoCompletionPort()函數創建一個完成端口,而且在一般情況下,我們需要并且只需要
建立一個完成端口,把他的句柄保存好, 之后只要使用這一個句柄就行了。
2根據和客戶的I/O操作最好是自己建一個工作線程
3接入Socket連接, 有兩種方式,1是和別的模型一樣,有一個獨立的線程,專門來accept客戶端的連接,
二是用性能更好的異步AcceptEx()請求
4每當有客戶端進來的時候,還是調用CreateIoCompletionPort()函數,這里不是建立完成端口,
而是把新連入的Socket句柄, 和你創建的完成端口綁定在一起。
5客戶端連入后,我們要向這個客戶端Socket提交一個請求,如接收文件要調用WSARecv()然后系統
就會去執行接收數據的操作, 就不用我們管了。
6 然后就要調用GetQueuedCompletionStatus()(是一個阻塞函數)里面是掃描端口的隊列里是否有
網絡通信的請求存在(例如讀取數據,發送數據等),一旦有,就會將這個請求從完成端口的隊列取回來,
繼續執行本線程的后續代碼,處理完畢后, 必須要再次 投遞網絡通信請求(WSARecv),如此循環。
5AcceptEx和Accept的區別
AcceptEx和Accept最大的區別,就是取消了阻塞方式的accept調用,也就是說AccentEx也是通過
完成端口來異步完成的。
這樣做的好處就是:如果短時間內客戶端并發連接請求不是很多,accept和AcceptEx在性能上區別不大,
雖然我們創建Socket只用一行SOCKET s =socket(...)一行代碼,但是系統內部建立一個Socket是相當
耗費資源的,因為Winsock2是分層的機構體系,創建一個Socket需要用到多個Provider之間進行處理,
最終形成一個可用的套接字,總之,創建一個Socket的開心是相當高的。
AcceptEx比Accept強三點:
(1)最關鍵的是AcceptEx在客戶端連入之前,就把客戶端的Socket建立好了,也就是說,AcceptEx是先建立
Socket,然后發出的AcceptEx調用,也就是說,在進行客戶端的通信之前,無論是否有客戶端連入,
Socket都是提前建立好的,而不需要想accept是在客戶端連入之后,在現場話費時間建立Socket,
(2)相比Accept只能阻塞方式建立一個連入的入口,對于大量的并發客戶端來講,是在是有點擠,
而AcceptEx可以在完成端口上投遞多個請求,還有客戶端連入的時候,就非常優雅而且從容.
(3)AcceptEx還有一個優點,就是投遞AccepEx的時候,收取客戶端發來的第一組數據,這是同時
進行的, 也就意味著,如果客戶端只是連入但不發送數據的話,我們就不會收到這個AccepeEx完成的通知,
異步的AcceptEx使用起來比accept要麻煩。
由于時間關系,在下篇博客 會詳細介紹完成端口的用法
實現圖片中的功能
參考博客地址 http://www.cnblogs.com/lancidie/archive/2011/12/19/2293773.html
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。