• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Jiang's C++ Space

            創(chuàng)作,也是一種學(xué)習(xí)的過(guò)程。

               :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::

            【20060407發(fā)表于blog.csdn.net,20090928重編輯】

            (博主:此為轉(zhuǎn)載文章,出處已經(jīng)記不清,內(nèi)容有些泛泛而談,僅供參考)

            一、客戶機(jī)/服務(wù)器模式

            在TCP/IP網(wǎng)絡(luò)中兩個(gè)進(jìn)程間的相互作用的主機(jī)模式是客戶機(jī)/服務(wù)器模式(Client/Server model)。該模式的建立基于以下兩點(diǎn):
            1、非對(duì)等作用;
            2、通信完全是異步的。
            客戶機(jī)/服務(wù)器模式在操作過(guò)程中采取的是主動(dòng)請(qǐng)示方式。

            服務(wù)器方要先啟動(dòng),并根據(jù)請(qǐng)示提供相應(yīng)服務(wù),過(guò)程如下:
            1、打開(kāi)一通信通道并告知本地主機(jī),它愿意在某一個(gè)公認(rèn)地址上接收客戶請(qǐng)求。
            2、等待客戶請(qǐng)求到達(dá)該端口。
            3、接收到重復(fù)服務(wù)請(qǐng)求,處理該請(qǐng)求并發(fā)送應(yīng)答信號(hào)。
            4、返回第二步,等待另一客戶請(qǐng)求
            5、關(guān)閉服務(wù)器。

            然后死客戶方:
            1、打開(kāi)一通信通道,并連接到服務(wù)器所在主機(jī)的特定端口。
            2、向服務(wù)器發(fā)送服務(wù)請(qǐng)求報(bào)文,等待并接收應(yīng)答;繼續(xù)提出請(qǐng)求……
            3、請(qǐng)求結(jié)束后關(guān)閉通信通道并終止。

            二、基本套接字

            為了更好說(shuō)明套接字編程原理,給出幾個(gè)基本的套接字,在以后的篇幅中會(huì)給出更詳細(xì)的使用說(shuō)明。

            1、創(chuàng)建套接字——socket()
            功能:使用前創(chuàng)建一個(gè)新的套接字
            格式:SOCKET PASCAL FAR socket(int af,int type,int procotol);
            af: 通信發(fā)生的區(qū)域
            type: 要建立的套接字類型
            procotol: 使用的特定協(xié)議

            2、指定本地地址——bind()
            功能:將套接字地址與所創(chuàng)建的套接字號(hào)聯(lián)系起來(lái)。
            格式:int PASCAL FAR bind(SOCKET s,const struct sockaddr FAR * name,int namelen);
            s: 是由socket()調(diào)用返回的并且未作連接的套接字描述符(套接字號(hào))。
            其它:沒(méi)有錯(cuò)誤,bind()返回0,否則SOCKET_ERROR

            地址結(jié)構(gòu)說(shuō)明:

            struct sockaddr_in
            {
             
            short sin_family;     //AF_INET
             u_short sin_port;     //16位端口號(hào),網(wǎng)絡(luò)字節(jié)順序
             struct in_addr sin_addr; //32位IP地址,網(wǎng)絡(luò)字節(jié)順序
             char sin_zero[8];     //保留
            }

            3、建立套接字連接——connect()和accept()
            功能:共同完成連接工作
            格式:int PASCAL FAR connect(SOCKET s,const struct sockaddr FAR * name,int namelen);
            格式:SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int FAR * addrlen);
            (參數(shù)同上)

            4、監(jiān)聽(tīng)連接——listen()
            功能:用于面向連接服務(wù)器,表明它愿意接收連接。
            格式:int PASCAL FAR listen(SOCKET s, int backlog);

            5、數(shù)據(jù)傳輸——send()與recv()
            功能:數(shù)據(jù)的發(fā)送與接收
            格式:int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int flags);
            格式:int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);
            buf:指向存有傳輸數(shù)據(jù)的緩沖區(qū)的指針。

            6、多路復(fù)用——select()
            功能:用來(lái)檢測(cè)一個(gè)或多個(gè)套接字狀態(tài)。
            格式:int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,
             fd_set FAR * exceptfds,const struct timeval FAR * timeout);
            readfds:指向要做讀檢測(cè)的指針
            writefds:指向要做寫檢測(cè)的指針
            exceptfds:指向要檢測(cè)是否出錯(cuò)的指針
            timeout:最大等待時(shí)間

            7、關(guān)閉套接字——closesocket()
            功能:關(guān)閉套接字s
            格式:BOOL PASCAL FAR closesocket(SOCKET s);

            三、典型過(guò)程圖

            2.1 面向連接的套接字的系統(tǒng)調(diào)用時(shí)序圖

            2.2 無(wú)連接協(xié)議的套接字調(diào)用時(shí)序圖

            2.3 面向連接的應(yīng)用程序流程圖

            四、WinSock簡(jiǎn)介

            Windows Sockets 是從 Berkeley Sockets 擴(kuò)展而來(lái)的,其在繼承 Berkeley Sockets 的基礎(chǔ)上,又進(jìn)行了新的擴(kuò)充。這些擴(kuò)充主要是提供了一些異步函數(shù),并增加了符合WINDOWS消息驅(qū)動(dòng)特性的網(wǎng)絡(luò)事件異步選擇機(jī)制。

            Windows Sockets由兩部分組成:開(kāi)發(fā)組件和運(yùn)行組件。
            開(kāi)發(fā)組件:Windows Sockets 實(shí)現(xiàn)文檔、應(yīng)用程序接口(API)引入庫(kù)和一些頭文件。
            運(yùn)行組件:Windows Sockets 應(yīng)用程序接口的動(dòng)態(tài)鏈接庫(kù)(WINSOCK.DLL)。

            五、WinSock主要擴(kuò)充說(shuō)明

            1、異步選擇機(jī)制
            Windows Sockets 的異步選擇函數(shù)提供了消息機(jī)制的網(wǎng)絡(luò)事件選擇,當(dāng)使用它登記網(wǎng)絡(luò)事件發(fā)生時(shí),應(yīng)用程序相應(yīng)窗口函數(shù)將收到一個(gè)消息,消息中指示了發(fā)生的網(wǎng)絡(luò)事件,以及與事件相關(guān)的一些信息。Windows Sockets 提供了一個(gè)異步選擇函數(shù) WSAAsyncSelect(),用它來(lái)注冊(cè)應(yīng)用程序感興趣的網(wǎng)絡(luò)事件,當(dāng)這些事件發(fā)生時(shí),應(yīng)用程序相應(yīng)的窗口函數(shù)將收到一個(gè)消息。

            函數(shù)結(jié)構(gòu)如下:
            int PASCAL FAR WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);
            hWnd:窗口句柄
            wMsg:需要發(fā)送的消息
            lEvent:事件(以下為事件的內(nèi)容)

            事件值含義:
            FD_READ 期望在套接字上收到數(shù)據(jù)(即讀準(zhǔn)備好)時(shí)接到通知
            FD_WRITE 期望在套接字上可發(fā)送數(shù)據(jù)(即寫準(zhǔn)備好)時(shí)接到通知
            FD_OOB 期望在套接字上有帶外數(shù)據(jù)到達(dá)時(shí)接到通知
            FD_ACCEPT 期望在套接字上有外來(lái)連接時(shí)接到通知
            FD_CONNECT 期望在套接字連接建立完成時(shí)接到通知
            FD_CLOSE 期望在套接字關(guān)閉時(shí)接到通知

            例如:我們要在套接字讀準(zhǔn)備好或?qū)憸?zhǔn)備好時(shí)接到通知,語(yǔ)句如下:
            rc=WSAAsyncSelect(s,hWnd,wMsg,FD_READ|FD_WRITE);
            如果我們需要注銷對(duì)套接字網(wǎng)絡(luò)事件的消息發(fā)送,只要將 lEvent 設(shè)置為0

            2、異步請(qǐng)求函數(shù)
            在 Berkeley Sockets 中請(qǐng)求服務(wù)是阻塞的,WINDOWS SICKETS 除了支持這一類函數(shù)外,還增加了相應(yīng)的異步請(qǐng)求函數(shù)——WSAAsyncGetXByY。

            3、阻塞處理方法
            Windows Sockets 為了實(shí)現(xiàn)當(dāng)一個(gè)應(yīng)用程序的套接字調(diào)用處于阻塞時(shí),能夠放棄CPU讓其它應(yīng)用程序運(yùn)行,它在調(diào)用處于阻塞時(shí)便進(jìn)入一個(gè)叫“HOOK”的例程,此例程負(fù)責(zé)接收和分配WINDOWS消息,使得其它應(yīng)用程序仍然能夠接收到自己的消息并取得控制權(quán)。

            WINDOWS 是非搶先的多任務(wù)環(huán)境,即若一個(gè)程序不主動(dòng)放棄其控制權(quán),別的程序就不能執(zhí)行。因此在設(shè)計(jì)Windows Sockets 程序時(shí),盡管系統(tǒng)支持阻塞操作,但還是反對(duì)程序員使用該操作。但由于 SUN 公司下的 Berkeley Sockets 的套接字默認(rèn)操作是阻塞的,WINDOWS 作為移植的 SOCKETS 也不可避免對(duì)這個(gè)操作支持。

            在Windows Sockets 實(shí)現(xiàn)中,對(duì)于不能立即完成的阻塞操作做如下處理:DLL初始化→循環(huán)操作。在循環(huán)中,它發(fā)送任何 WINDOWS 消息,并檢查這個(gè) Windows Sockets 調(diào)用是否完成,在必要時(shí),它可以放棄CPU讓其它應(yīng)用程序執(zhí)行(當(dāng)然使用超線程的CPU就不會(huì)有這個(gè)麻煩了^_^)。我們可以調(diào)用 WSACancelBlockingCall() 函數(shù)取消此阻塞操作。

            在 Windows Sockets 中,有一個(gè)默認(rèn)的阻塞處理例程 BlockingHook() 簡(jiǎn)單地獲取并發(fā)送 WINDOWS 消息。如果要對(duì)復(fù)雜程序進(jìn)行處理,Windows Sockets 中還有 WSASetBlockingHook() 提供用戶安裝自己的阻塞處理例程能力;與該函數(shù)相對(duì)應(yīng)的則是 WSAUnhookBlockingHook(),它用于刪除先前安裝的任何阻塞處理例程,并重新安裝默認(rèn)的處理例程。請(qǐng)注意,設(shè)計(jì)自己的阻塞處理例程時(shí),除了函數(shù) WSACancelBlockingHook() 之外,它不能使用其它的 Windows Sockets API 函數(shù)。在處理例程中調(diào)用 WSACancelBlockingHook()函數(shù)將取消處于阻塞的操作,它將結(jié)束阻塞循環(huán)。

            4、出錯(cuò)處理

            Windows Sockets 為了和以后多線程環(huán)境(WINDOWS/UNIX)兼容,它提供了兩個(gè)出錯(cuò)處理函數(shù)來(lái)獲取和設(shè)置當(dāng)前線程的最近錯(cuò)誤號(hào)。(WSAGetLastEror()和WSASetLastError())

            5、啟動(dòng)與終止

            使用函數(shù) WSAStartup() 和 WSACleanup() 啟動(dòng)和終止套接字。

            六、Windows Sockets網(wǎng)絡(luò)程序設(shè)計(jì)核心

            我們終于可以開(kāi)始真正的 Windows Sockets 網(wǎng)絡(luò)程序設(shè)計(jì)了。不過(guò)我們還是先看一看每個(gè) Windows Sockets 網(wǎng)絡(luò)程序都要涉及的內(nèi)容。讓我們一步步慢慢走。

            1、啟動(dòng)與終止

            在所有Windows Sockets函數(shù)中,只有啟動(dòng)函數(shù)WSAStartup()和終止函數(shù)WSACleanup()是必須使用的。啟動(dòng)函數(shù)必須是第一個(gè)使用的函數(shù),而且它允許指定 Windows Sockets API 的版本,并獲得 SOCKETS的特定的一些技術(shù)細(xì)節(jié)。本結(jié)構(gòu)如下:

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

            其中 wVersionRequested 保證 SOCKETS 可正常運(yùn)行的 DLL 版本,如果不支持,則返回錯(cuò)誤信息。我們看一下下面這段代碼,看一下如何進(jìn)行 WSAStartup() 的調(diào)用:

            WORD wVersionRequested; // 定義版本信息變量
            WSADATA wsaData; //定義數(shù)據(jù)信息變量
            int err; //定義錯(cuò)誤號(hào)變量
            wVersionRequested = MAKEWORD(1,1);//給版本信息賦值
            err = WSAStartup(wVersionRequested, &wsaData);//給錯(cuò)誤信息賦值
            if(err!=0)
            {
              
            return;//告訴用戶找不到合適的版本
            }
            //確認(rèn) Windows Sockets DLL 支持 1.1 版本
            //DLL 版本可以高于 1.1
            //系統(tǒng)返回的版本號(hào)始終是最低要求的 1.1,即應(yīng)用程序與DLL 中可支持的最低版本號(hào)
            if(LOBYTE(wsaData.wVersion)!= 1|| HIBYTE(wsaData.wVersion)!=1)
            {
              WSACleanup();
            //告訴用戶找不到合適的版本
              return;
            }
            //Windows Sockets DLL 被進(jìn)程接受,可以進(jìn)入下一步操作

            關(guān)閉函數(shù)使用時(shí),任何打開(kāi)并已連接的 SOCK_STREAM 套接字被復(fù)位,但那些已由 closesocket() 函數(shù)關(guān)閉的但仍有未發(fā)送數(shù)據(jù)的套接字不受影響,未發(fā)送的數(shù)據(jù)仍將被發(fā)送。程序運(yùn)行時(shí)可能會(huì)多次調(diào)用 WSAStartuo() 函數(shù),但必須保證每次調(diào)用時(shí)的 wVersionRequested 的值是相同的。

            2、異步請(qǐng)求服務(wù)

            Windows Sockets 除支持 Berkeley Sockets 中同步請(qǐng)求,還增加了了一類異步請(qǐng)求服務(wù)函數(shù) WSAAsyncGerXByY()。該函數(shù)是阻塞請(qǐng)求函數(shù)的異步版本。應(yīng)用程序調(diào)用它時(shí),由 Windows Sockets DLL 初始化這一操作并返回調(diào)用者,此函數(shù)返回一個(gè)異步句柄,用來(lái)標(biāo)識(shí)這個(gè)操作。當(dāng)結(jié)果存儲(chǔ)在調(diào)用者提供的緩沖區(qū),并且發(fā)送一個(gè)消息到應(yīng)用程序相應(yīng)窗口。常用結(jié)構(gòu)如下:

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

            需要注意的是,由于 Windows 的內(nèi)存對(duì)像可以設(shè)置為可移動(dòng)和可丟棄,因此在操作內(nèi)存對(duì)象是,必須保證 WIindows Sockets DLL 對(duì)象是可用的。

            3、異步數(shù)據(jù)傳輸

            使用 send() 或 sendto() 函數(shù)來(lái)發(fā)送數(shù)據(jù),使用 recv() 或recvfrom() 來(lái)接收數(shù)據(jù)。Windows Sockets 不鼓勵(lì)用戶使用阻塞方式傳輸數(shù)據(jù),因?yàn)槟菢涌赡軙?huì)阻塞整個(gè) Windows 環(huán)境。下面我們看一個(gè)異步數(shù)據(jù)傳輸實(shí)例。

            假設(shè)套接字 s 在連接建立后,已經(jīng)使用了函數(shù) WSAAsyncSelect() 在其上注冊(cè)了網(wǎng)絡(luò)事件 FD_READ 和 FD_WRITE,并且 wMsg 值為 UM_SOCK,那么我們可以在 Windows 消息循環(huán)中增加如下的分支語(yǔ)句:

            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、出錯(cuò)處理

            Windows 提供了一個(gè)函數(shù)來(lái)獲取最近的錯(cuò)誤碼 WSAGetLastError(),推薦的編寫方式如下:

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

             

            posted on 2009-09-28 11:09 Jiang Guogang 閱讀(804) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Windows Programming
            少妇精品久久久一区二区三区| 亚洲精品无码久久久久去q| 国产精品久久久久影院色| 久久66热人妻偷产精品9| 精品久久久久久无码专区| 久久精品亚洲一区二区三区浴池| 色诱久久久久综合网ywww| 久久久精品人妻一区二区三区蜜桃| 久久香蕉国产线看观看精品yw| 久久午夜伦鲁片免费无码| 久久成人国产精品一区二区| 亚洲精品综合久久| 亚洲精品国产自在久久| 久久99精品久久久久久久久久| 国产91久久综合| 久久精品国产免费观看| 99久久人人爽亚洲精品美女| 亚洲美日韩Av中文字幕无码久久久妻妇| 性高湖久久久久久久久AAAAA| 麻豆亚洲AV永久无码精品久久| 国产精品免费久久久久电影网| 国产精品久久久久久久app| 国产一区二区三区久久精品| 亚洲国产成人久久精品99 | 亚洲精品乱码久久久久久蜜桃图片 | 久久国产精品波多野结衣AV| 伊人久久精品无码二区麻豆| 久久青青草原综合伊人| 亚洲午夜久久久| 久久精品国产亚洲av麻豆小说| 精品亚洲综合久久中文字幕| 久久这里只有精品视频99| 无码人妻精品一区二区三区久久久| 亚洲午夜久久久精品影院| 久久精品国产精品亚洲毛片| 久久99精品久久久久久hb无码 | 久久精品视频网| 久久久久亚洲精品男人的天堂| 久久综合久久综合亚洲| 久久99九九国产免费看小说| 99久久er这里只有精品18|