當前位置:編程學習大全網 - 行動軟體 - Socket編程的幾種模式

Socket編程的幾種模式

其基本原理是:首先建立壹個socket連接,然後對其進行操作,比如,從該socket讀數據。因為網絡傳輸是要壹定的時間的,即使網絡通暢的情況下,接受數據的操作也要花費時間。對於壹個簡單的單線程程序,接收數據的過程是無法處理其他操作的。比如壹個窗口程序,當妳接收數據時,點擊按鈕或關閉窗口操作都不會有效。它的缺點顯而易見,壹個線程妳只能處理壹個 socket,用來教課還行,實際使用效果就不行了。select模型 為了處理多個socket連接,聰明的人們發明了select模型。該模型以集合來管理socket連接,每次去查詢集合中的socket狀態,從而達到處理多連接的能力,其函數原型是int select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout)。比如我們判斷某個socket是否有數據可讀,我們首先將壹個fdread集合置空,然後將socket加入到該集合,調用 select(0,&fdread,NULL,NULL,NULL),之後我們判斷socket是否還在fdread中,如果還在,則說明有數據可讀。數據的讀取和阻塞模型相同,調用recv函數。但是每個集合容量都有壹個限值,默認情況下是64個,當然妳可以重新定義它的大小,但還是有壹個最上限,自己設置也不能超過該值,壹般情況下是1024。盡管select模型可以處理多連接,但集合的管理多少讓人感到繁瑣。異步選擇模型 熟悉windows操作系統的都知道,其窗口處理是基於消息的。人們又發明了壹種新的網絡模型——WSAAsyncSelect模型,即異步選擇模型。該模型為每個socket綁定壹個消息,當socket上出現事先設置的socket事件時,操作系統就會給應用程序發送這個消息,從而對該 socket事件進行處理,其函數原型是int WSAAsynSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent)。hWnd指明接收消息的句柄,wMsg指定消息ID,lEvent按位設置感興趣的網絡事件,入 WSAAsyncSelect(s,hwnd,WM_SOCKET, FD_CONNECT | FD_READ | FD_CLOSE)。該模型的優點是在系統開銷不大的情況下同時處理許多連接,也不需要什麽集合管理。缺點很明顯,即使妳的程序不需要窗口,也要專門為 WSAAsyncSelect模型定義壹個窗口。另外,讓單個窗口去處理成千上萬的socket操作事件,很可能成為性能瓶頸。事件選擇模型 與WSAAsynSelect模型類似,人們還發明了WSAEventSelect模型,即事件選擇模型。看名字就可以猜測出來,它是基於事件的。WSAAsynSelect模型在出現感興趣的socket事件時,系統會發壹個相應的消息。而WSAEventSelect模型在出現感興趣的socket事件時,系統會將相應WSAEVENT事件設為傳信。可能妳現在對sokect事件和普通WSAEVENT事件還不是很清楚。 socket事件是與socket操作相關的壹些事件,如FD_READ,FD_WRITE,FD_ACCEPT等。而WSAEVENT事件是傳統的事件,該事件有兩種狀態,傳信(signaled)和未傳信(non-signaled)。所謂傳信,就是事件發生了,未傳信就是還沒有發生。我們每次建立壹個連接,都為其綁定壹個事件,等到該連接變化時,事件就會變為傳信狀態。那麽,誰去接受這個事件變化呢?我們通過壹個 WSAWaitForMultipleEvents(...)函數來等待事件發生,傳入參數中的事件數組中,只有有壹個事件發生,該函數就會返回(也可以設置為所有事件發生才返回,在這裏沒用),返回值為事件的數組序號,這樣我們就知道了哪個事件發生了,也就是該事件對應的socket有了socket操作事件。該模型比起WSAAsynSelect模型的優勢很明顯,不需要窗口。唯壹缺點是,該模型每次只能等待64個事件,這壹限制使得在處理多 socket時,有必要組織壹個線程池,伸縮性不如後面要講的重疊模型。重疊I/O(Overlapped I/O)模型重疊I/O(Overlapped I/O)模型使應用程序達到更佳的系統性能。重疊模型的基本設計原理是讓應用程序使用重疊數據結構,壹次投遞壹個或多個Winsock I/O請求。重疊模型到底是什麽東西呢?可以與WSAEventSelect模型做類比(其實不恰當,後面再說),事件選擇模型為每個socket連接綁定了壹個事件,而重疊模型為每個socket連接綁定了壹個重疊。當連接上發生socket事件時,對應的重疊就會被更新。其實重疊的高明之處在於,它在更新重疊的同時,還把網絡數據傳到了實現指定的緩存區中。我們知道,前面的網絡模型都要用戶自己通過recv函數來接受數據,這樣就降低了效率。我們打個比方,WSAEventSelect模型就像郵局的包裹通知,用戶收到通知後要自己去郵局取包裹。而重疊模型就像送貨上門,郵遞員發給妳通知時,也把包裹放到了妳事先指定的倉庫中。重疊模型又分為事件通知和完成例程兩種模式。在分析這兩種模式之前,我們還是來看看重疊數據結構:typedef struct WSAOVERLAPPED{DWORD Internal;DWORD InternalHigh;DWORD Offset;DWORD OffsetHigh;WSAEVENT hEvent;}WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;該數據結構中,Internal、InternalHigh、Offset、OffsetHigh都是系統使用的,用戶不用去管,唯壹關註的就是 hEvent。如果使用事件通知模式,那麽hEvent就指向相應的事件句柄。如果是完成例程模式,hEvent設為NULL。我們現在來看事件通知模式,首先創建壹個事件hEvent,並創建壹個重疊結構AcceptOverlapped,並設置AcceptOverlapped.hEvent = hEvent,DataBuf是我們事先設置的數據緩存區。調用 WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&AcceptOverlapped,NULL),則將AcceptSocket與AcceptOverlapped重疊綁定在了壹起。當接收到數據以後,hEvent就會設為傳信,而數據就會放到 DataBuf中。我們再通過WSAWaitForMultipleEvents(...)接收到該事件通知。這裏我們要註意,既然是基於事件通知的,那它就有壹個事件處理上限,壹般為64。完成例程和事件通知模式的區別在於,當相應的socket事件出現時,系統會調用用戶事先指定的回調函數,而不是設置事件。其實就是將WSARecv的最後壹個參數設為函數指針。該回調函數的原型如下:void CALLBACK CompletionROUTINE(DWORD dwError,DWORD cbTransferred,LPWSAOVERLAPPED lpOverlapped,DWORD dwFlags);其中,cbTransferred表示傳輸的字節數,lpOverlapped是發生socket事件的重疊指針。我們調用 WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&AcceptOverlapped,WorkerRoutine) 將AcceptSocket與WorkRoutine例程綁定。這裏有壹點小提示,當我們創建多個socket的連接時,最好把重疊與相應的數據緩存區用壹個大的數據結構放到壹塊,這樣,我們在例程中通過lpOverlapped指針就可以直接找到相應的數據緩存區。這裏要註意,不能將多個重疊使用同壹個數據緩存區,這樣在多個重疊都在處理時,就會出現數據混亂。完成端口模型 下面我們來介紹專門用於處理為數眾多socket連接的網絡模型——完成端口。因為需要做出大量的工作以便將socket添加到壹個完成端口,而其他方法的初始化步驟則省事多了,所以對新手來說,完成端口模型好像過於復雜了。然而,壹旦弄明白是怎麽回事,就會發現步驟其實並非那麽復雜。所謂完成端口,實際是Windows采用的壹種I/O構造機制,除套接字句柄之外,還可以接受其他東西。使用這種模式之前,首先要創建壹個I/O完成端口對象,該函數定義如下:HANDLE CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,DWORD CompletionKey,DWORD NumberOfConcurrentThreads);該函數用於兩個截然不同的目的:1)用於創建壹個完成端口對象。2)將壹個句柄同完成端口關聯到壹起。通過參數NumberOfConcurrentThreads,我們可以指定同時運行的線程數。理想狀態下,我們希望每個處理器各自負責壹個線程的運行,為完成端口提供服務,避免過於頻繁的線程任務切換。對於壹個socket連接,我們通過 CreateIoCompletionPort((HANDLE)Accept,CompletionPort, (DWORD)PerHandleData,0)將Accept連接與CompletionPort完成端口綁定到壹起,CompetionPort對應的那些線程不斷通過GetQueuedCompletionStatus來查詢與其關聯的socket連接是否有I/O操作完成,如果有,則做相應的數據處理,然後通過WSARecv將該socket連接再次投遞,繼續工作。完成端口在性能和伸縮性方面表現都很好,相關聯的socket連接數目沒有限制。

  • 上一篇:網上補課平臺哪個好
  • 下一篇:永恒戰士2之無雙戰神修改金幣的,銀幣修改已成功,金幣是0不知道怎麽弄,求攻略
  • copyright 2024編程學習大全網