傳統的Server/Client實現是基於Thread per request,即伺服器為每個用戶端請求建立一個線程處理,單獨負責處理一個客戶的請求。
大多數的網路遊戲的伺服器都會選擇非阻塞select這種結構,為什麼呢?因為網路遊戲的伺服器需要處理的串連非常之多,並且大部分會選擇在Linux/Unix下運行,那麼為每個使用者開一個線程實際上是很不划算的,一方面因為在Linux/Unix下的線程是用進程這麼一個概念類比出來的,比較消耗系統資源,另外除了I/O之外,每個線程基本上沒有什麼多餘的需要並行的任務,而且網路遊戲是互交性非常強的,所以線程間的同步會成為很麻煩的問題。由此一來,對於這種含有大量網路連接的單線程伺服器,用阻塞顯然是不現實的。
iocp,在linux下使用epoll
關於線程是這樣的,肯定不可能一個使用者一個線程的,沒見過那麼做的,通常我們是這樣的,我們建立幾個線程分別用於發送和接收網路訊息,當然數量也不是太多,通常是CPU個數的2倍,然後另外建立一個邏輯線程,所有的網路線程接收到的資料都會打入這個邏輯線程,以保證邏輯處理中的順序處理. 不知道你是否理解. 另外一個小提示,QQGAME可不是一個進程就500個串連,通常他一個進程都會達到20000左右的串連數.
NIO伺服器最核心的一點就是反應器模式:當有感興趣的事件發生的,就通知對應的事件處理器去處理這個事件,如果沒有,則不處理。所以使用一個線程做輪詢就可以了。當然這裡這是個例子,如果要獲得更高效能,可以使用少量的線程,一個負責接收請求,其他的負責處理請求,特別是對於多CPU時效率會更高。
JDK 7,WEB伺服器 Tomcat、Jetty等,在Windows下,Java將可以使用IOCP,而不是現在nio所用的select,網路並發效能將會得到大幅度提升。在Linux下則應該改變不多,畢竟linux現在並發最好效能的網路I/O EPOLL,JDK 6.0 nio包含5.0的後續版本的預設實現就是epoll。
-------------------
關於C++中完成連接埠的介紹:
完成連接埠在我理解看來也就是用來管理非同步程序呼叫的,呵呵!在Wait等待事件函數中存在數量限制,而完成連接埠不存在這一限制。
只給完成連接埠啟動2倍CPU的線程,這是因為線程也耗系統資源,在一個時間片內一個CPU上只會處理一個線程,大量的線程環境切換也很耗時間,設定2倍的線程,是因為線程處理常式可能會處理比較耗時的操作,這時如果完成連接埠又來了請求,系統就會喚醒線程池中的空閑線程及時響應,所以設定為2倍。說得夠明白了吧!^-^
兩個線程是處理絕對的並發請求,假如真的會有1000個並發請求,兩個線程同時處理也是非常快的,估計1-2秒就差不多了.
完成連接埠並不是為每個請求開一個線程,否則會把cpu累壞的.樓主沒真正理解.
當你的線程在諸如做資料庫調用的時候或者讀寫檔案,如果處於等待狀態,IOCP會啟用另外一個線程。所以不用太擔心。
完成連接埠的出發點之一就是減少效能線上程切換時的損失吧,好像有的例子裡面背景工作執行緒的個數是CPU*2+2,據說是實際測試出來的結果這樣的設定效率最高
完成連接埠
一個完成連接埠其實就是一個通知隊列,由作業系統把已經完成的重疊I/O請求的通知放入其中。當某項I/O操作一旦完成,某個可以對該操作結果進行處理的工作者線程就會收到一則通知。而通訊端在被建立後,可以在任何時候與某個完成連接埠進行關聯。
步驟:
1、建立一個空的完成連接埠;
2、得到本地機器的CPU個數;
3、開啟CPU*2個背景工作執行緒(又名線程池),全部都在等待完成連接埠的完成包;
4、建立TCP的監聽socket,使用事件邦定,建立監聽線程;
5、當有人串連進入的時候,將Client socket儲存到一個我們自己定義的關鍵鍵,
並把它與我們建立的完成連接埠關聯;
6、使用WSARecv和WSASend函數投遞一些請求,這是使用重疊I/O的方式;
7、重複5~6;
註:1、重疊I/O的方式中,接收與發送資料包的時候,一定要進行投遞請求這是它們這個體繫結構的特點 當然,在完成連接埠方式中,不是直接使用的WSARecv和WSASend函數進行請求的投遞的。而是使用的ReadFile,Write的方式
2、完成連接埠使用了系統內部的一些模型,所以我們只要按照一定的順序調用就可以完成了。
3、完成連接埠是使用在這樣的情況下,有成千上萬的使用者串連的時候,它能夠保證效能不會降低。
引文來源 Java與完成連接埠IOCP--流子