Windows Sockets 網路編程(三) —— WINDOWS SOCKETS 1.1 程式設計

來源:互聯網
上載者:User

一、簡介
WINDOWS SOCKETS 是從 Berkeley Sockets 擴充而來的,其在繼承 Berkeley Sockets 的基礎上,又進行了新的擴充。這些擴充主要是提供了一些非同步函數,並增加了符合WINDOWS訊息驅動特性的網路事件非同步選擇機制。
WINDOWS SOCKETS由兩部分組成:開發組件和運行組件。
開發組件:WINDOWS SOCKETS 實現文檔、應用程式介面(API)引入庫和一些標頭檔。
運行組件:WINDOWS SOCKETS 應用程式介面的動態連結程式庫(WINSOCK.DLL)。

 二、主要擴充說明

1、非同步選擇機制:
WINDOWS SOCKETS 的非同步選擇函數提供了訊息機制的網路事件選擇,當使用它登記網路事件發生時,應用程式相應視窗函數將收到一個訊息,訊息中指示了發生的網路事件,以及與事件相關的一些資訊。
WINDOWS SOCKETS 提供了一個非同步選擇函數 WSAAsyncSelect(),用它來註冊應用程式感興趣的網路事件,當這些事件發生時,應用程式相應的視窗函數將收到一個訊息。
函數結構如下:

int PASCAL FAR WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);

參數說明:
hWnd:視窗控制代碼
wMsg:需要發送的訊息
lEvent:事件(以下為事件的內容)
值: 含義:
FD_READ 期望在通訊端上收到資料(即讀準備好)時接到通知
FD_WRITE 期望在通訊端上可發送資料(即寫準備好)時接到通知
FD_OOB 期望在通訊端上有帶外資料到達時接到通知
FD_ACCEPT 期望在通訊端上有外來串連時接到通知
FD_CONNECT 期望在通訊端串連建立完成時接到通知
FD_CLOSE 期望在通訊端關閉時接到通知
例如:我們要在通訊端讀準備好或寫準備好時接到通知,語句如下:

rc=WSAAsyncSelect(s,hWnd,wMsg,FD_READ|FD_WRITE);

如果我們需要登出對通訊端網路事件的訊息發送,只要將 lEvent 設定為0 

2、非同步請求函數
在 Berkeley Sockets 中請求服務是阻塞的,WINDOWS SICKETS 除了支援這一類函數外,還增加了相應的非同步請求函數(WSAAsyncGetXByY();)。

3、阻塞處理方法
WINDOWS SOCKETS 為了實現當一個應用程式的通訊端調用處於阻塞時,能夠放棄CPU讓其它應用程式運行,它在調用處於阻塞時便進入一個叫“HOOK”的常式,此常式負責接收和分配WINDOWS訊息,使得其它應用程式仍然能夠接收到自己的訊息並取得控制權。
WINDOWS 是非搶先的多任務環境,即若一個程式不主動放棄其控制權,別的程式就不能執行。因此在設計 WINDOWS SOCKETS 程式時,儘管系統支援阻塞操作,但還是反對程式員使用該操作。但由於 SUN 公司下的 Berkeley Sockets 的通訊端預設操作是阻塞的,WINDOWS 作為移植的 SOCKETS 也不可避免對這個操作支援。
在 WINDOWS SOCKETS 實現中,對於不能立即完成的阻塞操作做如下處理:DLL初始化→迴圈操作。在迴圈中,它發送任何 WINDOWS 訊息,並檢查這個 WINDOWS SOCKETS 調用是否完成,在必要時,它可以放棄CPU讓其它應用程式執行(當然使用超執行緒的CPU就不會有這個麻煩了^_^)。我們可以調用 WSACancelBlockingCall() 函數取消此阻塞操作。
在 WINDOWS SOCKETS 中,有一個預設的阻塞處理常式 BlockingHook() 簡單地擷取並發送 WINDOWS 訊息。如果要對複雜程式進行處理,WINDOWS SOCKETS 中還有 WSASetBlockingHook() 提供使用者安裝自己的阻塞處理常式能力;與該函數相對應的則是 SWAUnhookBlockingHook(),它用於刪除先前安裝的任何阻塞處理常式,並重新安裝預設的處理常式。請注意,設計自己的阻塞處理常式時,除了函數 WSACancelBlockingHook() 之外,它不能使用其它的 WINDOWS SOCKETS API 函數。在處理常式中調用 WSACancelBlockingHook()函數將取消處於阻塞的操作,它將結束阻塞迴圈。

4、出錯處理
WINDOWS SOCKETS 為了和以後多線程環境(WINDOWS/UNIX)相容,它提供了兩個出錯處理函數來擷取和設定當前線程的最近錯誤號碼。(WSAGetLastEror()和WSASetLastError())

5、啟動與終止
使用函數 WSAStartup() 和 WSACleanup() 啟動和終止通訊端。

 三、WINDOWS SOCKETS 網路程式設計核心

我們終於可以開始真正的 WINDOWS SOCKETS 網路程式設計了。不過我們還是先看一看每個 WINDOWS SOCKETS 網路程式都要涉及的內容。讓我們一步步慢慢走。

1、啟動與終止
在所有 WINDOWS SOCKETS 函數中,只有啟動函數 WSAStartup() 和終止函數 WSACleanup() 是必須使用的。
啟動函數必須是第一個使用的函數,而且它允許指定 WINDOWS SOCKETS API 的版本,並獲得 SOCKETS的特定的一些技術細節。本結構如下:

int PASCAL FAR WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

其中 wVersionRequested 保證 SOCKETS 可正常啟動並執行 DLL 版本,如果不支援,則返回錯誤資訊。
我們看一下下面這段代碼,看一下如何進行 WSAStartup() 的調用

WORD wVersionRequested;// 定義版本資訊變數    WSADATA wsaData;//定義資料資訊變數    int err;//定義錯誤號碼變數    wVersionRequested = MAKEWORD(1,1);//給版本資訊賦值    err = WSAStartup(wVersionRequested, &wsaData);//給錯誤資訊賦值    if(err!=0)    {        return;//告訴使用者找不到合適的版本    }    //確認 WINDOWS SOCKETS DLL 支援 1.1 版本    //DLL 版本可以高於 1.1    //系統返回的版本號碼始終是最低要求的 1.1,即應用程式與DLL 中可支援的最低版本號碼    if(LOBYTE(wsaData.wVersion)!= 1|| HIBYTE(wsaData.wVersion)!=1)    {        WSACleanup();//告訴使用者找不到合適的版本        return;    }    //WINDOWS SOCKETS DLL 被進程接受,可以進入下一步操作

關閉函數使用時,任何開啟並已串連的 SOCK_STREAM 通訊端被複位,但那些已由 closesocket() 函數關閉的但仍有未發送資料的通訊端不受影響,未發送的資料仍將被發送。程式運行時可能會多次調用 WSAStartuo() 函數,但必須保證每次調用時的 wVersionRequested 的值是相同的。

2、非同步請求服務
WINDOWS SOCKETS 除支援 Berkeley Sockets 中同步請求,還增加了了一類非同步請求服務函數 WSAAsyncGerXByY()。該函數是阻塞請求函數的非同步版本。應用程式調用它時,由 WINDOWS SOCKETS DLL 初始化這一操作並返回調用者,此函數返回一個非同步控制代碼,用來標識這個操作。當結果儲存在調用者提供的緩衝區,並且發送一個訊息到應用程式相應視窗。常用結構如下:

    HANDLE taskHnd;    char hostname="rs6000";    taskHnd = WSAAsyncBetHostByName(hWnd,wMsg,hostname,buf,buflen);

需要注意的是,由於 Windows 的記憶體對像可以設定為可移動和可丟棄,因此在操作記憶體對象是,必須保證 WIindows Sockets DLL 對象是可用的。

3、非同步資料轉送
使用 send() 或 sendto() 函數來發送資料,使用 recv() 或recvfrom() 來接收資料。Windows Sockets 不鼓勵使用者使用阻塞方式傳輸資料,因為那樣可能會阻塞整個 Windows 環境。下面我們看一個非同步資料轉送執行個體:
假設通訊端 s 在串連建立後,已經使用了函數 WSAAsyncSelect() 在其上註冊了網路事件 FD_READ 和 FD_WRITE,並且 wMsg 值為 UM_SOCK,那麼我們可以在 Windows 訊息迴圈中增加如下的分支語句:

   case UM_SOCK:      switch(lParam)      {      case FD_READ:          len = recv(wParam,lpBuffer,length,0);          break;      case FD_WRITE:          while(send(wParam,lpBuffer,len,0)!=SOCKET_ERROR)          break;      }      break;

4、出錯處理
Windows 提供了一個函數來擷取最近的錯誤碼 WSAGetLastError(),推薦的編寫方式如下:

    len = send (s,lpBuffer,len,0);    of((len==SOCKET_ERROR)&&(WSAGetLastError()==WSAWOULDBLOCK)){...}

http://www.vckbase.com/document/viewdoc/?id=536

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.