windows網路程式設計經典入門 (轉)

gugu99發表於2008-07-25
windows網路程式設計經典入門 (轉)[@more@]

 

對於一個初學者,下面方法是經典。
  初學者建議不要用MFC提供的類,而用windows 做一個簡單和客戶端,這樣有助於對socket程式設計機制的理解。
  為了簡單起見,應用是基於MFC的標準對話方塊。
  Winsock用WINDOWS API實現:
  (1)伺服器端有兩個執行緒:
  主執行緒 — 你需要編寫以下來實現

  #defineWORK_EVENT  USER_MESSAGE+100  file://定義網路事件
  sockaddr_in  clientaddr; file://暫時存放客戶端
 
  file://自己定義訊息對映函式,將上面定義的網路事件對映到處理函式
  file://OnNetEvent為網路事件處理函式,它在下面定義
  ON_MESSAGE(NETWORK_EVENT, OnNetEvent); 

  在你對話方塊中的初始化函式中下面的初始化網路的子函式
  BOOL InitNetwork()  file://初始化網路
  {
  file://初始化TCP
  BOOL ret = Wtartup(MAKE(2,2), &wsaData);
    if(ret != 0)
  {
    MessageBox("初始化套接字失敗!");
  return FALSE;
  }

  file://建立伺服器端套接字
  SOCKET serverSocket
  = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(serverSocket == INVALID_SOCKET)
  {
 MessageBox("建立套接字失敗!");
 closesocket(m_Socket);
 WSACleanup();
 return FALSE;
  }

  file://繫結到本地一個埠上
  sockaddr_in localaddr;
 localaddr.sin_family = AF_INET;
 localaddr.sin_port = htons(1688);
 localaddr.sin_addr.s_addr = 0;
  if(bind(serverSocket ,(const struct sockaddr*)&localaddr, 
  sizeof(sockaddr)) == SOCKET_ERROR)
 {
 MessageBox("繫結地址失敗!");
 closesocket(m_Socket);
 WSACleanup();
 return FALSE;
 }

  file://註冊網路非同步事件,m_hWnd為應用程式的主對話方塊或主視窗的控制程式碼
  WSAAsync(serverSocket, m_hWnd, NETWORK_EVENT,
  FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE);

  listen(serverSocket, 5); file://設定偵聽
 
  return TRUE;
  }

  file://定義網路事件的響應函式
  void OnNetEvent(WPARAM wParam, LPARAM lParam)
  {
  file://呼叫API函式,得到網路事件型別
  int iEvent = WSAGETSELECTEVENT(lParam);
 
  file://得到發出此事件的客戶端套接字
  SOCKET pSock = (SOCKET)wParam;

  switch(iEvent)
  {
  case FD_ACCEPT: file://客戶端連線請求
  {
  OnAccept();

  break;
  }
  case FD_CLOSE:  file://客戶端斷開事件:
  {
  OnClose(pSock);
  break;
  }
  case FD_READ:  file://網路資料包到達事件
  {
  OnReceive(pSock);
  break;
  }
  case FD_WRITE:  file://傳送網路資料事件
  {
  OnSend(pSock);
  break;
  }
    default: break;
  }
  }

  void OnAccept(SOCET pSock)  file://響應客戶端連線請求函式
  {
  int len = sizeof(sockaddr);

  file://呼叫API函式,接受連線,並返回一個新套接字
  file://還可以獲得客戶端的IP地址
  SOCKET clientSocket = accept(serverSocket,
  (struct sockaddr*)&clientaddr, &len);

  file://為新的socket註冊非同步事件,注意沒有Accept事件
  if(WSAAsyncSelect(clientSocket ,m_hWnd, IP_EVENT,
  FD_CLOSE | FD_READ | FD_WRITE) == SOCKET_ERROR)
 {
  MessageBox("註冊非同步事件失敗!");
  return;
 }
 
  file://自編函式,將此客戶端的相關資訊儲存下來:套接字、
  // IP地址、登陸時間 
  saveClientSocket(clientSocket,clientAddr,currentTimer);
  }

  void OnClose(SOCET pSock)
  {
  file://自編函式,結束與相應的客戶端的通訊,釋放相應資源並做相應處理
  endClientSocket(pSock);
  }

  void OnSend(SOCET pSock)
  {
  file://自編函式,在給客戶端發資料時做一些預處理
  handleOnSend(pSock);
  }

  void OnReceive(SOCET pSock)
  {
  recv(...);  file://呼叫API函式,讀出網路緩衝區中的資料包

  file://自編函式,將此資料包和發出此資料的客戶端
  file://clientSocket封裝成一條網路訊息
  buildNetMsg(...);

  file://自編函式,將此網路訊息放入一個訊息佇列中,由工作執行緒去處理
  saveNetMsg(...); 
  SetEvent(...);  file://用事件觸發工作執行緒
  } 
 
  客戶端登陸後,隨即把自己的名發給伺服器,伺服器接到後,把它儲存下來。這樣伺服器就可以顯示所有線上客戶端的資訊了,包括:客戶端計算機名、IP地址、登陸時間等。
 
  注意: 客戶端沒有OnAccept()函式,但有OnConnect()函式。

  工作執行緒 —
  在你的應用程式初始化時,建立並啟動一個工作執行緒

  AfxBeginThread(WorkThread,this,THREAD_PRIORITY_NORMAL);
  file://this可能為應用程式的主對話方塊或主視窗的控制程式碼

  UINT WorkThread(LPVOID pParam)
  { 
  while(1)
  { 
  file://等待多重事件到來
  int ret = WaitForMultiple(...); 
 
  switch(ret)
  {
  case OBJECT_0:
  { 
  if(bNewNetMsg) file://檢視網路訊息佇列是否有新的網路訊息
  {
  readNetMsg(...);  file://如有新的網路訊息,則讀出
  handleNetMsg(...);  file://處理此網路訊息
  }
  break;
  }
  case OBJECT_0 + 1:
  {
  file://做退出處理
  break;
  }
  default: break;
  }

  return 0;
  }
 
  客戶端為單執行緒,登陸伺服器時,用connect()函式給伺服器發連線請求;
  客戶端沒有OnAccept()函式,但有OnConnect()函式。
  在OnConnect()函式里做發連線請求時的預處理;
  在OnReceive()函式里響應並處理網路資料;
  在OnClose()函式里響應伺服器的關閉事件;
  在OnSend()函式里做發資料時的預處理;

  如果你還想實現各客戶端之間的線上交流(即所謂的室),你在客戶端還可以基於UDP協議
再做一套多點對多點的組播模型模型,以後在和你聊,你先把上面的程式實現。
 
  以上的I/O非同步模型基於Windows的訊息機制,另外還可以用事件模型、重疊模型或完成埠模型,
  建議你參考Windows網路程式設計指南之類的書。

  如果你能對上面的機制很熟練,你肯定已經對Winsock編網路程式的機制有一定理解,接下來你可以進行更精彩的程式設計, 不僅可以在網輸普通資料,而且還
以傳輸語音、影片資料,你還可以自己做一個聊天室,和你的同學在實驗室的區域網裡可以共同分享你的成果。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1007830/,如需轉載,請註明出處,否則將追究法律責任。

相關文章