在掌握了socket相關的一些函數後,套接字程式設計還是比較簡單的,日常工作中碰到很多的問題就是用戶端/伺服器模型中,如何讓服務端在同一時間高效的處理多個用戶端的連接配接,我們的處理辦法可能會是在服務端不停的監聽用戶端的請求,有新的請求到達時,開辟一個新的線程去和該用戶端進行後續處理,但是這樣針對每一個用戶端都需要去開辟一個新的線程,效率必定底下。
其實,socket程式設計提供了很多的模型來處理這種情形,我們隻要按照模型去實作我們的代碼就可以解決這個問題。主要有select模型和重疊I/o模型,以及完成端口模型。這次,我們主要介紹下select模型,該模型又分為普通select模型,wsaasyncselect模型,wsaeventselect模型。我們将通過樣例代碼的方式逐一介紹。
一、select模型
使用該模型時,在服務端我們可以開辟兩個線程,一個線程用來監聽用戶端的連接配接
請求,另一個用來處理用戶端的請求。主要用到的函數為select函數。如:
線程1處理函數:


線程2處理函數:


該模型有個最大的缺點就是,它需要一個死循環不停的去周遊所有的用戶端套接字集合,詢問是否有資料到來,這樣,如果連接配接的用戶端很多,勢必會影響處理用戶端請求的效率,但它的優點就是解決了每一個用戶端都去開辟新的線程與其通信的問題。如果有一個模型,可以不用去輪詢用戶端套接字集合,而是等待系統通知,當有用戶端資料到來時,系統自動的通知我們的程式,這就解決了select模型帶來的問題了。
二、WsaAsyncSelect模型
WsaAsyncSelect模型就是這樣一個解決了普通select模型問題的socket程式設計模型。它是在有用戶端資料到來時,系統發送消息給我們的程式,我們的程式隻要定義好消息的處理方法就可以了,用到的函數隻要是WSAAsyncSelect,如:
首先,我們定義一個Windows消息,告訴系統,當有用戶端資料到來時,發送該消息給我們。
在我們的處理函數中可以如下監聽用戶端的連接配接:


接下來,我們需要在我們的視窗添加對UM_SOCK_ASYNCRECVMSG消息的處理函數,在該函數中真正接收用戶端發送過來的資料,在這個消息處理函數中的wparam參數表示的是用戶端套接字,lparam參數表示的是發生的網絡事件如:


可以看到WsaAsyncSelect模型是非常簡單的模型,它解決了普通select模型的問題,但是它最大的缺點就是它隻能用在windows程式上,因為它需要一個接收系統消息的視窗句柄,那麼有沒有一個模型既可以解決select模型的問題,又不限定隻能是windows程式才能用呢?下面我們來看看WsaEventSelect模型。
三、WsaEventSelect模型
WsaEventSelect模型是一個不用主動去輪詢所有用戶端套接字是否有資料到來的模型,它也是在用戶端有資料到來時,系統發送通知給我們的程式,但是,它不是發送消息,而是通過事件的方式來通知我們的程式,這就解決了WsaAsyncSelect模型隻能用在windows程式的問題。
該模型的實作,我們也可以開辟兩個線程來進行處理,一個用來接收用戶端的連接配接請求,一個用來與用戶端進行通信,用到的主要函數有WSAEventSelect,WSAWaitForMultipleEvents,WSAEnumNetworkEvents實作方式如下:
首先定義三個全局數組
線程1處理函數如下:


線程2的處理函數如下:


該模型通過一個死循環裡面調用WSAWaitForMultipleEvents函數來等待用戶端套接字對應的Event的到來,一旦事件通知到達,就通過該套接字去接收資料。雖然WsaEventSelect模型的實作較前兩種方法複雜,但它在效率和相容性方面是最好的。
以上三種模型雖然在效率方面有了不少的提升,但它們都存在一個問題,就是都預設了隻能接收64個用戶端連接配接,雖然我們在實作時可以不受這個限制,但是那樣,它們所帶來的效率提升又将打折扣,那又有沒有什麼模型可以解決這個問題呢?我們的下一篇重疊I/0模型将解決這個問題