熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

入門基礎-VC網絡編程入門

2013-11-13 10:29:51  來源: .NET編程 

  對於許多初學者來說網絡通信程序的開發普遍的一個現象就是覺得難以入手許多概念諸如同步(Sync)/異步(Async)阻塞(Block)/非阻塞(Unblock)等初學者往往迷惑不清只知其所以而不知起所以然

  同步方式指的是發送方不等接收方響應便接著發下個數據包的通信方式而異步指發送方發出數據後等收到接收方發回的響應才發下一個數據包的通信方式

  阻塞套接字是指執行此套接字的網絡調用時直到成功才返回否則一直阻塞在此網絡調用上比如調用recv()函數讀取網絡緩沖區中的數據如果沒有數據到達將一直掛在recv()這個函數調用上直到讀到一些數據此函數調用才返回而非阻塞套接字是指執行此套接字的網絡調用時不管是否執行成功都立即返回比如調用recv()函數讀取網絡緩沖區中數據不管是否讀到數據都立即返回而不會一直掛在此函數調用上在實際Windows網絡通信軟件開發中異步非阻塞套接字是用的最多的平常所說的C/S(客戶端/服務器)結構的軟件就是異步非阻塞模式的

  對於這些概念初學者的理解也許只能似是而非我將用一個最簡單的例子說明異步非阻塞Socket的基本原理和工作機制目的是讓初學者不僅對Socket異步非阻塞的概念有個非常透徹的理解而且也給他們提供一個用Socket開發網絡通信應用程序的快速入門方法操作系統是Windows (或NT開發工具是Visual C++

  MFC提供了一個異步類CAsyncSocket它封裝了異步非阻塞Socket的基本功能用它做常用的網絡通信軟件很方便但它屏蔽了Socket的異步非阻塞等概念開發人員無需了解異步非阻塞Socket的原理和工作機制因此建議初學者學習編網絡通信程序時暫且不要用MFC提供的類而先用Winsock API這樣有助於對異步非阻塞Socket編程機制的理解

  為了簡單起見服務器端和客戶端的應用程序均是基於MFC的標准對話框網絡通信部分基於Winsock API實現

  先做服務器端應用程序

  用MFC向導做一個基於對話框的應用程序SocketSever注意第三步中不要選上Windwos Sockets選項在做好工程後創建一個SeverSock將它設置為異步非阻塞模式並為它注冊各種網絡異步事件然後與自定義的網絡異步事件聯系上最後還要將它設置為監聽模式在自定義的網絡異步事件的回調函數中你可以得到各種網絡異步事件根據它們的類型做不同的處理下面將詳細介紹如何編寫相關代碼

  在SocketSeverDlgh文件的類定義之前增加如下定義

  #define NETWORK_EVENT WM_USER+ 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://異步事件回調函數

  …

  };

  在SocketSeverDlgcpp文件中增加消息映射其中OnNetEvent是異步事件回調函數名

  ON_MESSAGE(NETWORK_EVENTOnNetEvent)

  定義初始化網絡函數在SocketSeverDlgcpp文件的OnInitDialog()中調此函數即可

  BOOL CSocketSeverDlg::InitNetwork()

  {

  WSADATA wsaData;

  file://初始化TCP協議

  BOOL ret = WSAStartup(MAKEWORD() &wsaData);

  if(ret != )

  {

  MessageBox(初始化網絡協議失敗!);

  return FALSE;

  }

  file://創建服務器端套接字

  ServerSock = socket(AF_INET SOCK_STREAM IPPROTO_TCP);

  if(ServerSock == INVALID_SOCKET)

  {

  MessageBox(創建套接字失敗!);

  closesocket(ServerSock);

  WSACleanup();

  return FALSE;

  }

  file://綁定到本地一個端口上

  sockaddr_in localaddr;

  localaddrsin_family = AF_INET;

  localaddrsin_port = htons(); file://端口號不要與其他應用程序沖突

  localaddrsin_addrs_addr = ;

  if(bind(ServerSock (struct sockaddr*)&localaddrsizeof(sockaddr))

  = = SOCKET_ERROR)

  {

  MessageBox(綁定地址失敗!);

  closesocket(ServerSock);

  WSACleanup();

  return FALSE;

  file://將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 ); file://設置偵聽模式

  return TRUE;

  }

  下面定義網絡異步事件的回調函數

  void CSocketSeverDlg::OnNetEvent(WPARAM wParam LPARAM lParam)

  {

  file://調用Winsock API函數得到網絡事件類型

  int iEvent = WSAGETSELECTEVENT(lParam);

  file://調用Winsock API函數得到發生此事件的客戶端套接字

  SOCKET CurSock= (SOCKET)wParam;

  switch(iEvent)

  {

  case FD_ACCEPT: file://客戶端連接請求事件

  OnAccept(CurSock);

  break;

  case FD_CLOSE: file://客戶端斷開事件:

  OnClose(CurSock);

  break;

  case FD_READ: file://網絡數據包到達事件

  OnReceive(CurSock);

  break;

  case FD_WRITE: file://發送網絡數據事件

  OnSend(CurSock);

  break;

  default: break;

  }

  }

  以下是發生在相應Socket上的各種網絡異步事件的處理函數其中OnAccept傳進來的參數是服務器端創建的套接字OnClose()OnReceive()和OnSend()傳進來的參數均是服務器端在接受客戶端連接時新創建的用與此客戶端通信的Socket

  void CSocketSeverDlg::OnAccept(SOCKET CurSock)

  {

  file://接受連接請求並保存與發起連接請求的客戶端進行通信Socket

  file://為新的socket注冊異步事件注意沒有Accept事件

  }

  void CSocketSeverDlg::OnClose(SOCET CurSock)

  {

  file://結束與相應的客戶端的通信釋放相應資源

  }

  void CSocketSeverDlg::OnSend(SOCET CurSock)

  {

  file://在給客戶端發數據時做相關預處理

  }

  void CSocketSeverDlg::OnReceive(SOCET CurSock)

  {

  file://讀出網絡緩沖區中的數據包

  }

  用同樣的方法建立一個客戶端應用程序初始化網絡部分不需要將套接字設置為監聽模式注冊異步事件時沒有FD_ACCEPT但增加了FD_CONNECT事件因此沒有OnAccept()函數但增加了OnConnect()函數向服務器發出連接請求時使用connect()函數連接成功後會響應到OnConnect()函數中下面是OnConnect()函數的定義傳進來的參數是客戶端Socket和服務器端發回來的連接是否成功的標志

  void CSocketClntDlg::OnConnect(SOCKET CurSock int error)

  {

  if( = = error)

  {

  if(CurSock = = ClntSock)

  MessageBox(連接服務器成功!);

  }

  }

  定義OnReceive()函數處理網絡數據到達事件;

  定義OnSend()函數處理發送網絡數據事件;

  定義OnClose()函數處理服務器的關閉事件

  以上就是用基於Windows消息機制的異步I/O模型做服務器和客戶端應用程序的基本方法另外還可以用事件模型重疊模型或完成端口模型讀者可以參考有關書籍

  在實現了上面的例子後你將對Winsock編網絡通信程序的機制有了一定的了解接下來你可以進行更精彩的編程 不僅可以在網上傳輸普通數據而且還以傳輸語音視頻數據你還可以自己做一個網絡資源共享的服務器軟件和你的同學在實驗室的局域網裡可以共同分享你的成果


From:http://tw.wingwit.com/Article/program/net/201311/13815.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.