<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    weidagang2046的專(zhuān)欄

    物格而后知致
    隨筆 - 8, 文章 - 409, 評(píng)論 - 101, 引用 - 0
    數(shù)據(jù)加載中……

    Winsock開(kāi)發(fā)網(wǎng)絡(luò)通信程序的經(jīng)典入門(mén)

    對(duì)于許多初學(xué)者來(lái)說(shuō),網(wǎng)絡(luò)通信程序的開(kāi)發(fā),普遍的一個(gè)現(xiàn)象就是覺(jué)得難以入手。許多概念,諸如:同步(Sync)/異步(Async),阻塞(Block)/非阻塞(Unblock)等,初學(xué)者往往迷惑不清,只知其所以而不知起所以然。

      同步方式指的是發(fā)送方不等接收方響應(yīng),便接著發(fā)下個(gè)數(shù)據(jù)包的通信方式;而異步指發(fā)送方發(fā)出數(shù)據(jù)后,等收到接收方發(fā)回的響應(yīng),才發(fā)下一個(gè)數(shù)據(jù)包的通信方式。

      阻塞套接字是指執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),直到成功才返回,否則一直阻塞在此網(wǎng)絡(luò)調(diào)用上,比如調(diào)用recv()函數(shù)讀取網(wǎng)絡(luò)緩沖區(qū)中的數(shù)據(jù),如果沒(méi)有數(shù)據(jù)到達(dá),將一直掛在recv()這個(gè)函數(shù)調(diào)用上,直到讀到一些數(shù)據(jù),此函數(shù)調(diào)用才返回;而非阻塞套接字是指執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),不管是否執(zhí)行成功,都立即返回。比如調(diào)用recv()函數(shù)讀取網(wǎng)絡(luò)緩沖區(qū)中數(shù)據(jù),不管是否讀到數(shù)據(jù)都立即返回,而不會(huì)一直掛在此函數(shù)調(diào)用上。在實(shí)際Windows網(wǎng)絡(luò)通信軟件開(kāi)發(fā)中,異步非阻塞套接字是用的最多的。平常所說(shuō)的C/S(客戶端/服務(wù)器)結(jié)構(gòu)的軟件就是異步非阻塞模式的。

      對(duì)于這些概念,初學(xué)者的理解也許只能似是而非,我將用一個(gè)最簡(jiǎn)單的例子說(shuō)明異步非阻塞Socket的基本原理和工作機(jī)制。目的是讓初學(xué)者不僅對(duì)Socket異步非阻塞的概念有個(gè)非常透徹的理解,而且也給他們提供一個(gè)用Socket開(kāi)發(fā)網(wǎng)絡(luò)通信應(yīng)用程序的快速入門(mén)方法。操作系統(tǒng)是Windows 98(或NT4.0),開(kāi)發(fā)工具是Visual C++6.0。

      MFC提供了一個(gè)異步類(lèi)CAsyncSocket,它封裝了異步、非阻塞Socket的基本功能,用它做常用的網(wǎng)絡(luò)通信軟件很方便。但它屏蔽了Socket的異步、非阻塞等概念,開(kāi)發(fā)人員無(wú)需了解異步、非阻塞Socket的原理和工作機(jī)制。因此,建議初學(xué)者學(xué)習(xí)編網(wǎng)絡(luò)通信程序時(shí),暫且不要用MFC提供的類(lèi),而先用Winsock2 API,這樣有助于對(duì)異步、非阻塞Socket編程機(jī)制的理解。

      為了簡(jiǎn)單起見(jiàn),服務(wù)器端和客戶端的應(yīng)用程序均是基于MFC的標(biāo)準(zhǔn)對(duì)話框,網(wǎng)絡(luò)通信部分基于Winsock2 API實(shí)現(xiàn)。

      先做服務(wù)器端應(yīng)用程序。

      用MFC向?qū)ё鲆粋€(gè)基于對(duì)話框的應(yīng)用程序SocketSever,注意第三步中不要選上Windwos Sockets選項(xiàng)。在做好工程后,創(chuàng)建一個(gè)SeverSock,將它設(shè)置為異步非阻塞模式,并為它注冊(cè)各種網(wǎng)絡(luò)異步事件,然后與自定義的網(wǎng)絡(luò)異步事件聯(lián)系上,最后還要將它設(shè)置為監(jiān)聽(tīng)模式。在自定義的網(wǎng)絡(luò)異步事件的回調(diào)函數(shù)中,你可以得到各種網(wǎng)絡(luò)異步事件,根據(jù)它們的類(lèi)型,做不同的處理。下面將詳細(xì)介紹如何編寫(xiě)相關(guān)代碼。

      在SocketSeverDlg.h文件的類(lèi)定義之前增加如下定義: #define NETWORK_EVENT WM_USER+166 file://定義網(wǎng)絡(luò)事件

    SOCKET ServerSock; file://服務(wù)器端Socket

      在類(lèi)定義中增加如下定義:

    class CSocketSeverDlg : CDialog
    {
     public:
      SOCKET ClientSock[CLNT_MAX_NUM]; file://存儲(chǔ)與客戶端通信的Socket的數(shù)組

      /*各種網(wǎng)絡(luò)異步事件的處理函數(shù)*/
      void OnClose(SOCKET CurSock); file://對(duì)端Socket斷開(kāi)
      void OnSend(SOCKET CurSock); file://發(fā)送網(wǎng)絡(luò)數(shù)據(jù)包
      void OnReceive(SOCKET CurSock); file://網(wǎng)絡(luò)數(shù)據(jù)包到達(dá)
      void OnAccept(SOCKET CurSock); file://客戶端連接請(qǐng)求

      BOOL InitNetwork(); file://初始化網(wǎng)絡(luò)函數(shù)
      void OnNetEvent(WPARAM wParam, LPARAM lParam); file://異步事件回調(diào)函數(shù)
      …
    };

      在SocketSeverDlg.cpp文件中增加消息映射,其中OnNetEvent是異步事件回調(diào)函數(shù)名:

    ON_MESSAGE(NETWORK_EVENT,OnNetEvent)

      定義初始化網(wǎng)絡(luò)函數(shù),在SocketSeverDlg.cpp文件的OnInitDialog()中調(diào)此函數(shù)即可。

    BOOL CSocketSeverDlg::InitNetwork()
    {
     WSADATA wsaData;

     //初始化TCP協(xié)議
     BOOL ret = WSAStartup(MAKEWORD(2,2), &wsaData);
     if(ret != 0)
     {
      MessageBox("初始化網(wǎng)絡(luò)協(xié)議失敗!");
      return FALSE;
     }

     //創(chuàng)建服務(wù)器端套接字
     ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if(ServerSock == INVALID_SOCKET)
     {
      MessageBox("創(chuàng)建套接字失敗!");
      closesocket(ServerSock);
      WSACleanup();
      return FALSE;
     }

     //綁定到本地一個(gè)端口上
     sockaddr_in localaddr;
     localaddr.sin_family = AF_INET;
     localaddr.sin_port = htons(8888); //端口號(hào)不要與其他應(yīng)用程序沖突
     localaddr.sin_addr.s_addr = 0;
     if(bind(ServerSock ,(struct sockaddr*)&localaddr,sizeof(sockaddr))= = SOCKET_ERROR)
     {
      MessageBox("綁定地址失敗!");
      closesocket(ServerSock);
      WSACleanup();
      return FALSE;
     }

     //將SeverSock設(shè)置為異步非阻塞模式,并為它注冊(cè)各種網(wǎng)絡(luò)異步事件,其中m_hWnd
     //為應(yīng)用程序的主對(duì)話框或主窗口的句柄
     if(WSAAsyncSelect(ServerSock, m_hWnd, NETWORK_EVENT, FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE) == SOCKET_ERROR)
     {
      MessageBox("注冊(cè)網(wǎng)絡(luò)異步事件失敗!");
      WSACleanup();
      return FALSE;
     }
     listen(ServerSock, 5); file://設(shè)置偵聽(tīng)模式
     return TRUE;
    }

      下面定義網(wǎng)絡(luò)異步事件的回調(diào)函數(shù)

    void CSocketSeverDlg::OnNetEvent(WPARAM wParam, LPARAM lParam)
    {
     //調(diào)用Winsock API函數(shù),得到網(wǎng)絡(luò)事件類(lèi)型
     int iEvent = WSAGETSELECTEVENT(lParam);

     //調(diào)用Winsock API函數(shù),得到發(fā)生此事件的客戶端套接字
     SOCKET CurSock= (SOCKET)wParam;

     switch(iEvent)
     {
      case FD_ACCEPT: //客戶端連接請(qǐng)求事件
       OnAccept(CurSock);
       break;
      case FD_CLOSE: //客戶端斷開(kāi)事件:
       OnClose(CurSock);
       break;
      case FD_READ: //網(wǎng)絡(luò)數(shù)據(jù)包到達(dá)事件
       OnReceive(CurSock);
       break;
      case FD_WRITE: //發(fā)送網(wǎng)絡(luò)數(shù)據(jù)事件
       OnSend(CurSock);
       break;
      default: break;
     }
    }

      以下是發(fā)生在相應(yīng)Socket上的各種網(wǎng)絡(luò)異步事件的處理函數(shù),其中OnAccept傳進(jìn)來(lái)的參數(shù)是服務(wù)器端創(chuàng)建的套接字,OnClose()、OnReceive()和OnSend()傳進(jìn)來(lái)的參數(shù)均是服務(wù)器端在接受客戶端連接時(shí)新創(chuàng)建的用與此客戶端通信的Socket。

    void CSocketSeverDlg::OnAccept(SOCKET CurSock)
    {
     //接受連接請(qǐng)求,并保存與發(fā)起連接請(qǐng)求的客戶端進(jìn)行通信Socket
     //為新的socket注冊(cè)異步事件,注意沒(méi)有Accept事件
    }

    void CSocketSeverDlg::OnClose(SOCET CurSock)
    {
     //結(jié)束與相應(yīng)的客戶端的通信,釋放相應(yīng)資源
    }

    void CSocketSeverDlg::OnSend(SOCET CurSock)
    {
     //在給客戶端發(fā)數(shù)據(jù)時(shí)做相關(guān)預(yù)處理
    }

    void CSocketSeverDlg::OnReceive(SOCET CurSock)
    {
     //讀出網(wǎng)絡(luò)緩沖區(qū)中的數(shù)據(jù)包
    }

      用同樣的方法建立一個(gè)客戶端應(yīng)用程序。初始化網(wǎng)絡(luò)部分,不需要將套接字設(shè)置為監(jiān)聽(tīng)模式。注冊(cè)異步事件時(shí),沒(méi)有FD_ACCEPT,但增加了FD_CONNECT事件,因此沒(méi)有OnAccept()函數(shù),但增加了OnConnect()函數(shù)。向服務(wù)器發(fā)出連接請(qǐng)求時(shí),使用connect()函數(shù),連接成功后,會(huì)響應(yīng)到OnConnect()函數(shù)中。下面是OnConnect()函數(shù)的定義,傳進(jìn)來(lái)的參數(shù)是客戶端Socket和服務(wù)器端發(fā)回來(lái)的連接是否成功的標(biāo)志。

    void CSocketClntDlg::OnConnect(SOCKET CurSock, int error)
    {
     if(0 = = error)
     {
      if(CurSock = = ClntSock)
       MessageBox("連接服務(wù)器成功!");
     }
    }

      ·定義OnReceive()函數(shù),處理網(wǎng)絡(luò)數(shù)據(jù)到達(dá)事件;

      ·定義OnSend()函數(shù),處理發(fā)送網(wǎng)絡(luò)數(shù)據(jù)事件;

      ·定義OnClose()函數(shù),處理服務(wù)器的關(guān)閉事件。

      以上就是用基于Windows消息機(jī)制的異步I/O模型做服務(wù)器和客戶端應(yīng)用程序的基本方法。另外還可以用事件模型、重疊模型或完成端口模型,讀者可以參考有關(guān)書(shū)籍。

      在實(shí)現(xiàn)了上面的例子后,你將對(duì)Winsock編網(wǎng)絡(luò)通信程序的機(jī)制有了一定的了解。接下來(lái)你可以進(jìn)行更精彩的編程, 不僅可以在網(wǎng)上傳輸普通數(shù)據(jù),而且還以傳輸語(yǔ)音、視頻數(shù)據(jù),你還可以自己做一個(gè)網(wǎng)絡(luò)資源共享的服務(wù)器軟件,和你的同學(xué)在實(shí)驗(yàn)室的局域網(wǎng)里可以共同分享你的成果。

    from: http://soft.yesky.com/165/2284165.shtml

    posted on 2006-09-28 13:17 weidagang2046 閱讀(267) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Windows

    主站蜘蛛池模板: 日韩a毛片免费观看| 国产精品亚洲一区二区三区| 无码国产精品一区二区免费I6| 亚洲一区二区三区在线观看网站| 国产男女猛烈无遮挡免费视频| 国产免费福利体检区久久| 中文字幕亚洲色图| 精品免费国产一区二区| 男女一进一出抽搐免费视频| 亚洲精品亚洲人成在线麻豆| 日本特黄特色免费大片| 中文字幕无码免费久久| 亚洲无码一区二区三区| 亚洲无码在线播放| 男人的好免费观看在线视频| 国产A∨免费精品视频| 亚洲国产成人手机在线电影bd| 国产精品va无码免费麻豆| 波多野结衣免费一区视频| 亚洲午夜精品久久久久久app| 亚洲欧洲成人精品香蕉网| 成人性生交视频免费观看| 中国毛片免费观看| 亚洲人成色99999在线观看| 亚洲色欲色欲www在线丝| 成全视频免费高清 | 99爱在线精品免费观看| 色老头综合免费视频| 亚洲理论片在线中文字幕| 亚洲国产人成中文幕一级二级| 最刺激黄a大片免费网站| 国产黄片不卡免费| 亚洲爆乳AAA无码专区| 182tv免费视频在线观看| jzzijzzij在线观看亚洲熟妇| 亚洲视频免费观看| 国产精品国产亚洲精品看不卡| 四虎永久成人免费| 成人av免费电影| 久草免费在线观看视频| 久章草在线精品视频免费观看|