• <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>

            依舊的博客

            技術(shù)學習

            C++博客 首頁 新隨筆 聯(lián)系 聚合 管理
              17 Posts :: 1 Stories :: 2 Comments :: 0 Trackbacks

            1. 客戶-服務(wù)器通信中的基本問題

            客戶和服務(wù)器通信是為了使用服務(wù),為此在傳輸機制的基礎(chǔ)上設(shè)計協(xié)議,通過對通信行為的規(guī)范,實現(xiàn)通信的目的,并解決傳輸中的問題。

            傳輸機制通常由下層協(xié)議提供,根據(jù)不同的通信需要選擇不同的下層協(xié)議,這是一個基本的問題。對應(yīng)用協(xié)議來說,可用的傳輸機制有可靠連接的字節(jié)流類型和不可靠無連接的數(shù)據(jù)報類型。

            服務(wù)器處理大量客戶的請求,從而并發(fā)是服務(wù)器的一個基本問題,如何處理這個問題也取決于通信需要。處理方式上,服務(wù)器可以是循環(huán)的或并發(fā)的,并發(fā)服務(wù)器有多種實現(xiàn)方式(異步I/O,多線程和多進程)。

            一件事情能無重復(fù)地連續(xù)進行,通常會獲得更好的效率,這要求主體始終知道當前的狀態(tài)。一次通信過程的連續(xù)性取決于通信雙方,它們都要知道通信進行的狀態(tài)。這對客戶一般不成問題,但服務(wù)器要和大量客戶通信,不一定能為每個客戶的每次通信保存狀態(tài)。如果服務(wù)器是有狀態(tài)的,那么就更快地計算響應(yīng),減少通信的數(shù)據(jù)量。但是傳輸和客戶的故障使有狀態(tài)服務(wù)器面臨很大問題,當傳輸不可靠(報文重復(fù),丟失,亂序)時,服務(wù)器維護的狀態(tài)會和客戶失去一致,一個不斷崩潰重啟的客戶會造成狀態(tài)信息不能發(fā)揮作用,而維護開銷卻極大增加。

            這就提出了客戶-服務(wù)器通信中的三個基本問題,它們的解決方案都取決于實際需要,客戶-服務(wù)器通信中有哪些情況的需要呢?

            • 是否要求可靠傳輸;
            • 是否需要服務(wù)器進行大量處理。對循環(huán)服務(wù)器進行分析可以知道,需要大量處理的通信用循環(huán)方案可能會丟失請求,用并發(fā)方案還可以提高服務(wù)器資源利用率,改善性能,只要少量處理的通信則無法忍受開銷大的解決方案。
            • 在局域網(wǎng)還是互聯(lián)網(wǎng)環(huán)境下,局域網(wǎng)中傳輸很少出錯,互聯(lián)網(wǎng)環(huán)境則不然;


            通常根據(jù)前兩個基本問題把服務(wù)器實現(xiàn)分為四種類型,它們的適用范圍如下:

            • 循環(huán)無連接服務(wù)器,少量處理的通信時,并且在局域網(wǎng)中或不要求可靠傳輸。這種做法主要是為了避免開銷。
            • 循環(huán)連接服務(wù)器,較少用,主要是循環(huán)的方式不夠高效,因為連接有一定開銷,響應(yīng)時間可能不低。在少量處理并要求可靠性的情況下使用。
            • 并發(fā)無連接服務(wù)器,很少用,因為要給每個請求開線程,開銷太大。在不要求可靠性的情況下,如果線程開銷遠小于計算響應(yīng)開銷,或者并發(fā)可以讓各請求的I/O并行,或者循環(huán)方案會丟失請求時可以考慮。
            • 并發(fā)連接服務(wù)器,常用。


            2. winsock基本函數(shù)的使用

            winsock的基本函數(shù)有WSAStartup(),WSACleanup(),socket(),closesocket(),bind(),listen(),accept(), connect(),send()和recv()。

            使用這些函數(shù),客戶端的大概算法是,

            1.  調(diào)用WSAStartup()初始化winsock庫。
            2.  調(diào)用socket()創(chuàng)建套接字,返回套接字描述符s。
            3.  指定遠程套接字地址sa,對s調(diào)用connect(),向sa標識的服務(wù)進程請求連接。
            4.  連接成功后,對s調(diào)用send()發(fā)送請求,調(diào)用recv()接收響應(yīng),如此反復(fù)直到完成任務(wù)。
            5.  對s調(diào)用closesocket()關(guān)閉連接。
            6.  不再發(fā)起連接處理新的任務(wù)時,調(diào)用WSACleanup()釋放winsock庫。

            服務(wù)器端的大概算法是,

            1. 調(diào)用WSAStartup()初始化winsock庫。
            2. 調(diào)用socket()創(chuàng)建套接字,返回套接字描述符s。
            3. 對s調(diào)用bind(),將其綁定到本地的套接字sa。
            4. 調(diào)用listen(),將s置為被動模式。此時開始偵聽客戶端的連接請求,將其放入一個隊列。
            5. 對s調(diào)用accept(),即從請求隊列中取出一項,接受該連接后返回一個新的套接字描述符s',以及對應(yīng)客戶端的套接字地址sa'。
            6. 對s'調(diào)用recv()接收請求,調(diào)用send()發(fā)送響應(yīng),如此反復(fù)直到完成任務(wù)。
            7. 對s'調(diào)用closesocket()關(guān)閉該連接。
            8. 重復(fù)5到7的過程。
            9. 從8退出后,調(diào)用WSACleanup()釋放winsock庫。

            有以下幾點需要進一步說明,

            1). 客戶端調(diào)用connect()和服務(wù)器端調(diào)用accept()成功后將在客戶進程和服務(wù)器進程之間建立一個TCP連接。連接兩端的每個套接字描述符都包含一個本地端點地址和一個遠程端點地址。所以在使用連接套接字發(fā)送數(shù)據(jù)時不用指示目的地址。

            2). 多宿主主機的IP地址選擇問題。從上面的算法容易提出這樣的問題,為什么客戶端在使用套接字時不綁定端點地址?通常的主機只有一個IP,但是多宿主主機有多個IP地址,在這種情況下,客戶端為套接字指定的IP可能與實際發(fā)送時經(jīng)過的IP不符,所以允許客戶端不指定套接字地址,而由TCP/IP軟件在實際發(fā)送時指定IP,同時選擇一個未用過的端口號,這正是在connect()調(diào)用中完成的。那么服務(wù)器端就不存在同樣的情況嗎?不是,在它調(diào)用bind()時指定一個套接字地址,其端口部分采用應(yīng)用協(xié)議的熟知端口,而IP地址部分有著同樣的問題。為此定義了一個代表統(tǒng)配地址的常量INADDR_ANY,用它指示IP地址部分。實際使用的IP仍然是由TCP/IP軟件分配。

            3). TCP為一個連接的發(fā)送端和接收端各維護一個緩沖區(qū)。當發(fā)送端緩沖區(qū)滿的時候,send()調(diào)用會阻塞,在接收端緩沖區(qū)為空的時候,recv()調(diào)用會阻塞。為什么要在通信進程和TCP連接之間維護一個間接層呢?可能是為了在一端有多個進程要使用信道的情況下,在多個進程之間進行信道分配的協(xié)調(diào)。比如在發(fā)送端,信道傳輸數(shù)據(jù)時send()調(diào)用可以繼續(xù)執(zhí)行,多個進程的send()調(diào)用同緩沖區(qū)打交道,彼此影響不大,因為讀寫緩沖區(qū)速度很快,而信道同緩沖區(qū)打交道,這時可以對各進程的發(fā)送數(shù)據(jù)進行協(xié)調(diào),實現(xiàn)公平的信道分配。另外,在TCP中有滑動窗口概念,是用于流量控制的,前述緩沖區(qū)和滑動窗口有什么關(guān)系?我現(xiàn)在不太清楚。

            4). 套接字的關(guān)閉問題。在客戶機和服務(wù)器通過TCP連接完成數(shù)據(jù)交換后,有一個安全關(guān)閉的問題。一方面,服務(wù)器不能關(guān)閉連接,因為客戶機可能還有請求,另一方面,客戶機雖然知道何時不再請求,但是它不知道服務(wù)器的響應(yīng)何時發(fā)送完,因為有些應(yīng)用協(xié)議的響應(yīng)數(shù)據(jù)量不確定。為此采用部分關(guān)閉的辦法,雖然連接是雙向的,但是允許在一個方向上關(guān)閉它,當客戶端不再請求時,可以部分關(guān)閉連接,使服務(wù)器收到一個信號,如果響應(yīng)發(fā)送完了,服務(wù)器就可以關(guān)閉連接,此時連接被完全關(guān)閉

            3. 套接字接口中的端點地址

            端點地址用來表示通信的進程,是傳輸層協(xié)議及其套接字接口中的重要概念。不同的協(xié)議族可以用不同方式表示端點地址,一個協(xié)議族還可以有多個地址族,每個地址族的地址格式不同。TCP/IP只有一個地址族,它的端點地址包括一個32位IP地址和一個16位端口號。在協(xié)議族和地址族的基礎(chǔ)上,套接字接口用更為具體的結(jié)構(gòu)來表示端點地址。

            套接字是一種適用于多個協(xié)議族的接口,并允許一個協(xié)議族使用多個地址族。TCP/IP協(xié)議族及其唯一地址族的標識分別是PF_INET和AF_INET。由于套接字接口的通用性,它提供一個通用的地址結(jié)構(gòu),其格式為(地址族,該族中的套接字地址)。套接字作為一個接口標準,可以有不同實現(xiàn),以下我們只討論windows套接字。

            如下定義的sockaddr實現(xiàn)了前述通用地址結(jié)構(gòu),

            // winsock2.h

            struct sockaddr {
                    u_short sa_family;              /* address family */
                    char    sa_data[14];            /* up to 14 bytes of direct address */
            };

            sockaddr的通用性是相對的,某些地址族不適合這個結(jié)構(gòu)。

            盡管sockaddr適合于TCP/IP協(xié)議族,但是winsock還定義了TCP/IP專用的地址格式,

            // winsock2.h

            struct sockaddr_in {
                    short   sin_family;
                    u_short sin_port;
                    struct  in_addr sin_addr;
                    char    sin_zero[8];
            };

            sin_family域取值恒為AF_INET。其中的in_addr結(jié)構(gòu)表示IP地址,定義如下,

            //winsock2.h

            struct in_addr {
                    union {
                            struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
                            struct { u_short s_w1,s_w2; } S_un_w;
                            u_long S_addr;
                    } S_un;
            #define s_addr  S_un.S_addr
                                            /* can be used for most TCP & IP code */
            #define s_host  S_un.S_un_b.s_b2
                                            /* host on imp */
            #define s_net   S_un.S_un_b.s_b1
                                            /* network */
            #define s_imp   S_un.S_un_w.s_w2
                                            /* imp */
            #define s_impno S_un.S_un_b.s_b4
                                            /* imp # */
            #define s_lh    S_un.S_un_b.s_b3
                                            /* logical host */
            };

            為了保證軟件的可移植性與可維護性,訪問TCP/IP的代碼不應(yīng)使用sockaddr。只使用TCP/IP的應(yīng)用程序可以只使用sockaddr_in,而永遠不用sockaddr。

            4. winsock程序?qū)嵗?/p>

            《vc6技術(shù)內(nèi)幕》的例程ex34a包括一個web服務(wù)器和三個客戶,服務(wù)器用winsock實現(xiàn),一個客戶用winsock,另兩個用wininet。我們以winsock實現(xiàn)的服務(wù)器和客戶為例。

            CBlockingSocket對各接口函數(shù)進行封裝,使它們的調(diào)用可以統(tǒng)一報錯。把錯誤檢查和函數(shù)調(diào)用一起封裝可以避免每次調(diào)用這些函數(shù)時都檢錯。為統(tǒng)一報錯,采用了異常機制,在檢出錯誤后拋出異常,然后統(tǒng)一進行異常處理。異常機制使我們可以把錯誤檢查和錯誤處理分開,檢查必須是分散的,但是處理可以適當集中,使代碼簡化。

            CHttpBlockingSocket根據(jù)接收http報文的特點對CBlockingSocket進行了擴展。成員函數(shù)ReadHttpHeaderLine()可以從TCP連接中按行接收字符(它引入了一個緩沖區(qū),緩沖區(qū)中收到的字符構(gòu)成一行后再輸出。該緩沖區(qū)的長度需要能夠容納每一行字符,溢出時報錯。接收輸出行的緩沖區(qū)也可能長度不足,這時接收的數(shù)據(jù)不足一行,在調(diào)用ReadHttpHeaderLine()時要注意這一點),ReadHttpResponse()用于接收首部行之后所有的響應(yīng),當調(diào)用者提供的緩沖區(qū)不足時會報錯。緩沖區(qū)不足的情況都是在CBlockingSocket::Receive()函數(shù)中檢測到的,該函數(shù)調(diào)用以上層次中的代碼按照正常情況編寫。

            CSockAddr是一個與sockaddr_in同樣用途的類,但是用法更方便。winsock函數(shù)使用的端點地址結(jié)構(gòu)是sockaddr,sockaddr_in本身用來代替它,所以CSockAddr需要能夠替代sockaddr。sockaddr可能用在傳值或傳址參數(shù)中,CSockAddr必須在邏輯上和存儲上都和sockaddr有等價性,并實現(xiàn)有關(guān)強制類型轉(zhuǎn)換。CSockAddr還實現(xiàn)了和sockaddr, sockaddr_in互相轉(zhuǎn)換的成員函數(shù),因為一種結(jié)構(gòu)很難在所有情況下都好用,新結(jié)構(gòu)也需要和舊結(jié)構(gòu)保持兼容。

             

            本例中采用服務(wù)器關(guān)閉套接字的辦法,因為每次連接只處理一個請求。

            參考:

            《用TCP/IP進行網(wǎng)際互聯(lián)第三卷(windows套接字版)》/清華出版社

            《vc6技術(shù)內(nèi)幕 5th ed》/希望電子出版社

            posted on 2006-05-02 12:46 依舊的博客 閱讀(2280) 評論(0)  編輯 收藏 引用 所屬分類: 編程
            超级碰碰碰碰97久久久久| 久久婷婷五月综合色高清| 99久久人人爽亚洲精品美女| 精品国产一区二区三区久久| 色综合合久久天天综合绕视看| 久久99国产精品久久99| 国产一区二区精品久久岳| 人妻中文久久久久| 久久人爽人人爽人人片AV| 国产精品久久国产精麻豆99网站| 国产呻吟久久久久久久92| 精品伊人久久大线蕉色首页| 999久久久无码国产精品| 久久久久久噜噜精品免费直播| 亚洲一区精品伊人久久伊人| 99久久这里只有精品| 久久精品国产欧美日韩99热| 99久久er这里只有精品18| 久久婷婷五月综合色99啪ak| 久久精品国产亚洲av影院| 欧美久久综合九色综合| 久久精品视频网| 中文字幕热久久久久久久| 精品水蜜桃久久久久久久| 精品免费久久久久久久| 性做久久久久久久久久久| 亚洲国产精品热久久| 久久无码人妻一区二区三区| 久久久久99这里有精品10| 欧美久久一级内射wwwwww.| 狠狠久久综合伊人不卡| 青草影院天堂男人久久| 精品国产VA久久久久久久冰| 久久久久久久波多野结衣高潮| 精品久久久久久无码国产| 久久久久综合网久久| 精品久久久久久中文字幕| 99国产欧美久久久精品蜜芽| av无码久久久久不卡免费网站 | 久久久久亚洲AV成人网人人网站| 国产精品国色综合久久|