TCP非阻塞socket程式設計

2021-04-18 19:46:29 字數 3788 閱讀 8660

網路通訊程式的同步方式指的是傳送方不等接收方響應,便接著發下個資料報的通訊方式;而非同步指傳送方發出資料後,等收到接收方發回的響應,才發下乙個資料報的通訊方式。 阻塞套接字是指執行此套接字的網路呼叫時,直到成功才返回,否則一直阻塞在此網路呼叫上,比如呼叫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工作在阻塞模式的時候,如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。非阻塞 非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不...