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

               C++ 技術(shù)中心

               :: 首頁 :: 聯(lián)系 ::  :: 管理
              160 Posts :: 0 Stories :: 87 Comments :: 0 Trackbacks

            公告

            鄭重聲明:本BLOG所發(fā)表的原創(chuàng)文章,作者保留一切權(quán)利。必須經(jīng)過作者本人同意后方可轉(zhuǎn)載,并注名作者(天空)和出處(CppBlog.com)。作者Email:coder@luckcoder.com

            留言簿(27)

            搜索

            •  

            最新隨筆

            最新評論

            評論排行榜

                  采用TCP連接的C/S模式軟件,連接的雙方在連接空閑狀態(tài)時,如果任意一方意外崩潰、當機、網(wǎng)線斷開或路由器故障,另一方無法得知TCP連接已經(jīng)失效,除非繼續(xù)在此連接上發(fā)送數(shù)據(jù)導致錯誤返回。很多時候,這不是我們需要的。我們希望服務(wù)器端和客戶端都能及時有效地檢測到連接失效,然后優(yōu)雅地完成一些清理工作并把錯誤報告給用戶。
                  如何及時有效地檢測到一方的非正常斷開,一直有兩種技術(shù)可以運用。一種是由TCP協(xié)議層實現(xiàn)的Keepalive,另一種是由應(yīng)用層自己實現(xiàn)的心跳包
                  TCP默認并不開啟Keepalive功能,因為開啟Keepalive功能需要消耗額外的寬帶和流量,盡管這微不足道,但在按流量計費的環(huán)境下增加了費用,另一方面,Keepalive設(shè)置不合理時可能會因為短暫的網(wǎng)絡(luò)波動而斷開健康的TCP連接。并且,默認的Keepalive超時需要7,200,000 milliseconds,即2小時,探測次數(shù)為5次。
                  對于Win2K/XP/2003,可以從下面的注冊表項找到影響整個系統(tǒng)所有連接的keepalive參數(shù):
                   [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters]
                    "KeepAliveTime”=dword:006ddd00
                    "KeepAliveInterval"=dword:000003e8 
                    "MaxDataRetries"="5"

                  對于實用的程序來說,2小時的空閑時間太長。因此,我們需要手工開啟Keepalive功能并設(shè)置合理的Keepalive參數(shù)。
            // 開啟KeepAlive
            BOOL bKeepAlive = TRUE;
            int nRet = ::setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&bKeepAlive, sizeof(bKeepAlive));

            if (nRet == SOCKET_ERROR)
            {
            return FALSE;
            }


            // 設(shè)置KeepAlive參數(shù)
            tcp_keepalive alive_in = {0};
            tcp_keepalive alive_out 
            = {0};
            alive_in.keepalivetime 
            = 5000// 開始首次KeepAlive探測前的TCP空閉時間

            alive_in.keepaliveinterval 
            = 1000// 兩次KeepAlive探測間的時間間隔

            alive_in.onoff 
            = TRUE;
            unsigned 
            long ulBytesReturn = 0;

            nRet 
            = WSAIoctl(socket_handle, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
            &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
            if (nRet == SOCKET_ERROR)
            {
            return FALSE;


            }



            開啟Keepalive選項之后,對于使用IOCP模型的服務(wù)器端程序來說,一旦檢測到連接斷開,GetQueuedCompletionStatus函數(shù)將立即返回FALSE,使得服務(wù)器端能及時清除該連接、釋放該連接相關(guān)的資源。對于使用select模型的客戶端來說,連接斷開被探測到時,以recv目的阻塞在socket上的select方法將立即返回SOCKET_ERROR,從而得知連接已失效,客戶端程序便有機會及時執(zhí)行清除工作、提醒用戶或重新連接。

             

            另一種技術(shù),由應(yīng)用程序自己發(fā)送心跳包來檢測連接的健康性。客戶端可以在一個Timer中或低級別的線程中定時向發(fā)服務(wù)器發(fā)送一個短小精悍的包,并等待服務(wù)器的回應(yīng)。客戶端程序在一定時間內(nèi)沒有收到服務(wù)器回應(yīng)即認為連接不可用,同樣,服務(wù)器在一定時間內(nèi)沒有收到客戶端的心跳包則認為客戶端已經(jīng)掉線。


             

             

            ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

             windows下此處的”非正常斷開”指TCP連接不是以優(yōu)雅的方式斷開,如網(wǎng)線故障等物理鏈路的原因,還有突然主機斷電等原因.

            有兩種方法可以檢測:

            1.TCP連接雙方定時發(fā)握手消息


            2.利用TCP協(xié)議棧中的KeepAlive探測
            第二種方法簡單可靠,只需對TCP連接兩個Socket設(shè)定KeepAlive探測,
            所以本文只講第二種方法在Linux,Window2000下的實現(xiàn)(在其它的平臺上沒有作進一步的測試)


            Windows 2000平臺下 頭文件
            #include 
            <mstcpip.h>
            //定義結(jié)構(gòu)及宏
            /*

            struct TCP_KEEPALIVE {
            u_longonoff;
            u_longkeepalivetime;
            u_longkeepaliveinterval;
            }
             ;
            */

                tcp_keepalive live,liveout; 
                live.keepaliveinterval=5000; //每5秒發(fā)一次探測報文,發(fā)5次沒有回應(yīng),就斷開
                live.keepalivetime=30000;//超過30s沒有數(shù)據(jù),就發(fā)送控測包
                
                live.onoff=TRUE; 
                int Opt = 1;
                int iRet = setsockopt(Accept,SOL_SOCKET,SO_KEEPALIVE,(char *)&Opt,sizeof(int)); 
                if(iRet == 0){
                 DWORD dw;
                 if(::WSAIoctl(Accept,SIO_KEEPALIVE_VALS,
                  &live,sizeof(live),&liveout,sizeof(liveout),
                  &dw,NULL,NULL)== SOCKET_ERROR){
                 } 
                }






            ACE下代碼 //by rainfish blog.csdn.net/bat603

            int Opt = 1;
            //在測試過程中,發(fā)現(xiàn)檢測的次數(shù)是5次,即下面的設(shè)置中,從最近一次消息開始計算的10秒后,每次間隔5秒,連續(xù)發(fā)送5次,即35秒發(fā)現(xiàn)網(wǎng)絡(luò)斷了
            tcp_keepalive live,liveout;
            live.keepaliveinterval=5000; //每次檢測的間隔 (單位毫秒)
            live.keepalivetime=10000; //第一次開始發(fā)送的時間(單位毫秒)
            live.onoff=TRUE;
            int iRet = stream.set_option(SOL_SOCKET,SO_KEEPALIVE,&Opt,sizeof(int));
            if(iRet == 0){
            DWORD dw;
            //此處顯示了在ACE下獲取套接字的方法,即句柄的(SOCKET)化就是句柄
            if(WSAIoctl((SOCKET)h,SIO_KEEPALIVE_VALS,&live,sizeof(live),
            &liveout,sizeof(liveout),&dw,NULL,NULL)== SOCKET_ERROR){
            //Delete Client
            return;
            }
            }


            Linux平臺下


            #include "/usr/include/linux/tcp.h"
            #include "/usr/include/linux/socket.h"
            ////KeepAlive實現(xiàn),單位秒
            //下面代碼要求有ACE,如果沒有包含ACE,則請把用到的ACE函數(shù)改成linux相應(yīng)的接口
            int keepAlive = 1;//設(shè)定KeepAlive
            int keepIdle = 5;//開始首次KeepAlive探測前的TCP空閉時間
            int keepInterval = 5;//兩次KeepAlive探測間的時間間隔
            int keepCount = 3;//判定斷開前的KeepAlive探測次數(shù)
            if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1)
            {
            ACE_DEBUG ((LM_INFO,
            ACE_TEXT ("(%P|%t) setsockopt SO_KEEPALIVE error!/n")));
            }

            if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1)
            {
            ACE_DEBUG ((LM_INFO,
            ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPIDLE error!/n")));
            }

            if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1)
            {
            ACE_DEBUG ((LM_INFO,
            ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPINTVL error!/n")));
            }

            if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1)
            {
            ACE_DEBUG ((LM_INFO,
            ACE_TEXT ("(%P|%t)setsockopt TCP_KEEPCNT error!/n")));
            }

            ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            posted on 2013-08-13 09:03 C++技術(shù)中心 閱讀(6597) 評論(1)  編輯 收藏 引用 所屬分類: Windows 網(wǎng)絡(luò)編程

            Feedback

            # re: tcp連接探測Keepalive和心跳包 2013-08-15 08:41 永遇樂
            學習了  回復  更多評論
              

            亚洲国产精品热久久| 久久久久亚洲av无码专区喷水| 国产精品久久久久久搜索| 日本道色综合久久影院| 久久精品成人免费观看97| 久久综合亚洲色一区二区三区| 久久99精品久久久久久hb无码| 国产免费久久精品丫丫| 亚洲中文字幕无码久久综合网 | 精品免费tv久久久久久久| 91精品国产91久久久久久青草| 亚洲欧美成人久久综合中文网| 人妻无码久久一区二区三区免费 | 日韩久久久久中文字幕人妻| 久久婷婷五月综合国产尤物app| yellow中文字幕久久网| 亚洲中文精品久久久久久不卡 | 亚洲国产一成人久久精品| 国产精品久久久久乳精品爆| 日产精品久久久久久久性色| 亚洲国产综合久久天堂| 久久国产精品免费一区二区三区| 亚洲精品美女久久久久99| 久久综合精品国产一区二区三区| 国产精品美女久久久久网| 三上悠亚久久精品| 精产国品久久一二三产区区别 | 久久国产劲爆AV内射—百度| 久久精品国产99久久丝袜| 色噜噜狠狠先锋影音久久| 国产精品久久久久影视不卡| 久久精品一本到99热免费| 中文字幕久久波多野结衣av| 久久久亚洲AV波多野结衣| 欧美亚洲另类久久综合婷婷 | 无码人妻精品一区二区三区久久久| 国产毛片久久久久久国产毛片| 天天爽天天爽天天片a久久网| 久久久精品一区二区三区| 国产成人久久AV免费| 国内精品久久久久影院优|