網路通訊程式的同步方式指的是傳送方不等接收方響應,便接著發下個資料報的通訊方式;而非同步指傳送方發出資料後,等收到接收方發回的響應,才發下乙個資料報的通訊方式。 阻塞套接字是指執行此套接字的網路呼叫時,直到成功才返回,否則一直阻塞在此網路呼叫上,比如呼叫recv()函式讀取網路緩衝區中的資料,如果沒有資料到達,將一直掛在recv()這個函式呼叫上,直到讀到一些資料,此函式呼叫才返回;而非阻塞套接字是指執行此套接字的網路呼叫時,不管是否執行成功,都立即返回。比如呼叫recv()函式讀取網路緩衝區中資料,不管是否讀到資料都立即返回,而不會一直掛在此函式呼叫上。在實際windows網路通訊軟體開發中,非同步非阻塞套接字是用的最多的。平常所說的c/s(客戶端/伺服器)結構的軟體就是非同步非阻塞模式的。
用乙個最簡單的例子說明非同步非阻塞socket的基本原理和工作機制。目的是讓初學者不僅對socket非同步非阻塞的概念有個非常透徹的理解,而且也給他們提供乙個用socket開發網路通訊應用程式的快速入門方法。作業系統是windows 98(或nt4.0),開發工具是visual c++6.0。 mfc提供了乙個非同步類casyncsocket,它封裝了非同步、非阻塞socket的基本功能,用它做常用的網路通訊軟體很方便。但它遮蔽了socket的非同步、非阻塞等概念,開發人員無需了解非同步、非阻塞socket的原理和工作機制。因此,建議初學者學習編網路通訊程式時,暫且不要用mfc提供的類,而先用winsock2 api,這樣有助於對非同步、非阻塞socket程式設計機制的理解。 為了簡單起見,伺服器端和客戶端的應用程式均是基於mfc的標準對話方塊,網路通訊部分基於winsock2 api實現。 先做伺服器端應用程式。 用mfc嚮導做乙個基於對話方塊的應用程式socketsever,注意第三步中不要選上windwos sockets選項。在做好工程後,建立乙個seversock,將它設定為非同步非阻塞模式,並為它註冊各種網路非同步事件,然後與自定義的網路非同步事件聯絡上,最後還要將它設定為監聽模式。在自定義的網路非同步事件的**函式中,你可以得到各種網路非同步事件,根據它們的型別,做不同的處理。下面將詳細介紹如何編寫相關**。
在socketseverdlg.h檔案的類定義之前增加如下定義:
#define network_event wm_user+166 file://定義網路事件
socket serversock; file://伺服器端socket
在類定義中增加如下定義:
class csocketseverdlg : cdialog
public: socket clientsock[clnt_max_num]; file://儲存與客戶端通訊的socket的陣列
/*各種網路非同步事件的處理函式*/
void onclose(socket cursock); file://對端socket斷開
void onsend(socket cursock); file://傳送網路資料報
void onreceive(socket cursock); file://網路資料報到達
void onaccept(socket cursock); file://客戶端連線請求
bool initnetwork(); file://初始化網路函式
void onnetevent(wparam wparam, lparam lparam); file://非同步事件**函式
在socketseverdlg.cpp檔案中增加訊息對映,其中onnetevent是非同步事件**函式名:
on_message(network_event,onnetevent)
定義初始化網路函式,在socketseverdlg.cpp檔案的oninitdialog()中調此函式即可。
bool csocketseverdlg::initnetwork()
wsadata wsadata; file://初始化tcp協議
bool ret = wsastartup(makeword(2,2), &wsadata);
if(ret != 0)
messagebox("初始化網路協議失敗!");
return false;
//建立伺服器端套接字
serversock = socket(af_inet, sock_stream, ipproto_tcp);
if(serversock == invalid_socket)
messagebox("建立套接字失敗!");
closesocket(serversock);
wsacleanup();
return false;
://繫結到本地乙個埠上
sockaddr_in localaddr;
localaddr.sin_family = af_inet;
localaddr.sin_port = htons(8888);
://埠號不要與其他應用程式衝突
localaddr.sin_addr.s_addr = 0;
if(bind(serversock ,(struct sockaddr*)&localaddr,sizeof(sockaddr)) = = socket_error)
messagebox("繫結位址失敗!");
closesocket(serversock);
wsacleanup();
return false;
://將seversock設定為非同步非阻塞模式,並為它註冊各種網路非同步事件,其 中 m_hwnd file://為應用程式的主對話方塊或主視窗的控制代碼
if(wsaasyncselect(serversock, m_hwnd, network_event, fd_accept | fd_close | fd_read | fd_write) == socket_error)
messagebox("註冊網路非同步事件失敗!");
wsacleanup();
return false;
listen(serversock, 5);
://設定偵聽模式 return true;
下面定義網路非同步事件的**函式
void csocketseverdlg::onnetevent(wparam wparam, lparam lparam)
void csocketseverdlg::onclose(socet cursock)
void csocketseverdlg::onsend(socet cursock)
void csocketseverdlg::onreceive(socet cursock)
用同樣的方法建立乙個客戶端應用程式。初始化網路部分,不需要將套接字設定為監聽模式。
註冊非同步事件時,沒有fd_accept,但增加了fd_connect事件,因此沒有onaccept()函式,但增加了onconnect()函式。向伺服器發出連線請求時,使用connect()函式,連線成功後,會響應到onconnect()函式中。下面是onconnect()函式的定義,傳進來的引數是客戶端socket和伺服器端發回來的連線是否成功的標誌。
void csocketclntdlg::onconnect(socket cursock, int error)
if(0 = = error)
if(cursock = = clntsock)
messagebox("連線伺服器成功!");
定義onreceive()函式,處理網路資料到達事件; 定義onsend()函式,處理傳送網路資料事件; 定義onclose()函式,處理伺服器的關閉事件。
以上就是用基於windows訊息機制的非同步i/o模型做伺服器和客戶端應用程式的基本方法。另外還可以用事件模型、重疊模型或完成埠模型,讀者可以參考有關書籍。
非阻塞socket程式設計
socket程式設計中可能出現阻塞的呼叫有4個 1.write send sendto sendmsg sendv等,如果某個程序呼叫乙個阻塞的tcp套接字 預設設定 如果傳送緩衝區沒有空間,呼叫程序將會睡眠,直到有空間為止。如果tcp套接字是非阻塞的,且沒有空間可寫,則會返回乙個ewouleblo...
非阻塞socket程式設計
阻塞 阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。該程序被標記為睡眠狀態並被排程出去。函式只有在得到結果之後才會返回。當socket工作在阻塞模式的時候,如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。非阻塞 非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不...
非阻塞socket程式設計
阻塞 阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。該程序被標記為睡眠狀態並被排程出去。函式只有在得到結果之後才會返回。當socket工作在阻塞模式的時候,如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。非阻塞 非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不...