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

            yehao's Blog

            SOCKET CLOSE_WAIT狀態(tài)的說明

            CLOSE_WAIT出現(xiàn)的原因: 就是某一方在網(wǎng)絡(luò)連接斷開后,對(duì)等方?jīng)]有檢測到這個(gè)錯(cuò)誤(對(duì)方斷開)而沒有調(diào)用 closesocket,導(dǎo)致了這個(gè)狀態(tài)的出現(xiàn);
             
            斷開連接的時(shí)候:
                  當(dāng)發(fā)起主動(dòng)關(guān)閉的左邊這方發(fā)送一個(gè)FIN過去后,右邊被動(dòng)關(guān)閉的這方要回應(yīng)一個(gè)ACK,這個(gè)ACK是TCP回應(yīng)的(同時(shí)TCP向上層應(yīng)用程序提交一個(gè)ERROR,導(dǎo)致上面的SOCKET的send或者recv返回SOCKET_ERROR),而不是應(yīng)用程序發(fā)送的,此時(shí),被動(dòng)關(guān)閉的一方就處于CLOSE_WAIT狀態(tài)了。如果此時(shí)被動(dòng)關(guān)閉的這一方不再繼續(xù)調(diào)用closesocket,那么他就不會(huì)發(fā)送接下來的FIN,導(dǎo)致自己老是處于CLOSE_WAIT。只有被動(dòng)關(guān)閉的這一方調(diào)用了closesocket,才會(huì)發(fā)送一個(gè)FIN給主動(dòng)關(guān)閉的這一方,同時(shí)也使得自己的狀態(tài)變遷為LAST_ACK,待接收到主動(dòng)關(guān)閉方發(fā)送的ACK后,才會(huì)將SOCKET置為CLOSED。
            + expand sourceview plaincopy to clipboardprint?
            int nRet = recv(sockConnected, szRecvBuffer,sizeof(szRecvBuffer),0);   
            ///   
            /// 當(dāng)對(duì)方調(diào)用closesocket的時(shí)候,我的程序正在recv,  
            /// 這時(shí)候有可能對(duì)方發(fā)送的FIN包我沒有收到,而是由TCP代回了一個(gè)ACK包,  
            /// 所以我這邊程序進(jìn)入CLOSE_WAIT狀態(tài)。   
            /// 所以建議在這里判斷是否已出錯(cuò),是就主動(dòng)closesocket。   
            /// 因?yàn)榍懊嬉呀?jīng)設(shè)置了recv超時(shí)時(shí)間為30秒,那么如果真的是超時(shí)了,   
            /// 這里收到的錯(cuò)誤應(yīng)該是WSAETIMEDOUT,這種情況下也可以關(guān)閉連接的   
            if (nRet == SOCKET_ERROR)   
            {   
               TRACE_INFO(_T("=用recv接收發(fā)生Socket錯(cuò)誤="));   
               closesocket(sockConnected);   
               return FALSE;  
            }  
            int nRet = recv(sockConnected, szRecvBuffer,sizeof(szRecvBuffer),0);
            ///
            /// 當(dāng)對(duì)方調(diào)用closesocket的時(shí)候,我的程序正在recv,
            /// 這時(shí)候有可能對(duì)方發(fā)送的FIN包我沒有收到,而是由TCP代回了一個(gè)ACK包,
            /// 所以我這邊程序進(jìn)入CLOSE_WAIT狀態(tài)。
            /// 所以建議在這里判斷是否已出錯(cuò),是就主動(dòng)closesocket。
            /// 因?yàn)榍懊嬉呀?jīng)設(shè)置了recv超時(shí)時(shí)間為30秒,那么如果真的是超時(shí)了,
            /// 這里收到的錯(cuò)誤應(yīng)該是WSAETIMEDOUT,這種情況下也可以關(guān)閉連接的
            if (nRet == SOCKET_ERROR)
            {
               TRACE_INFO(_T("=用recv接收發(fā)生Socket錯(cuò)誤="));
               closesocket(sockConnected);
               return FALSE;
            }
              
            檢測到SOCKET_ORROR 則主動(dòng)調(diào)用closesocket() 關(guān)閉套接字;
            ***************************************************************
            首先我們知道,如果我們的Client程序處于CLOSE_WAIT狀態(tài)的話,說明套接字是被動(dòng)關(guān)閉的!
            因?yàn)槿绻荢erver端主動(dòng)斷掉當(dāng)前連接的話,那么雙方關(guān)閉這個(gè)TCP連接共需要四個(gè)packet:
                   Server ---> FIN ---> Client
                   Server <--- ACK <--- Client
                這時(shí)候Server端處于FIN_WAIT_2狀態(tài);而我們的程序處于CLOSE_WAIT狀態(tài)。
                   Server <--- FIN <--- Client
            這時(shí)Client發(fā)送FIN給Server,Client就置為LAST_ACK狀態(tài)。
                    Server ---> ACK ---> Client
            Server回應(yīng)了ACK,那么Client的套接字才會(huì)真正置為CLOSED狀態(tài)。


            我們的程序處于CLOSE_WAIT狀態(tài),而不是LAST_ACK狀態(tài),說明還沒有發(fā)FIN給Server,那么可能是在關(guān)閉連接之前還有許多數(shù)據(jù)要發(fā)送或者其他事要做,導(dǎo)致沒有發(fā)這個(gè)FIN packet。
            原因知道了,那么為什么不發(fā)FIN包呢,難道會(huì)在關(guān)閉己方連接前有那么多事情要做嗎?
            還有一個(gè)問題,為什么有數(shù)千個(gè)連接都處于這個(gè)狀態(tài)呢?難道那段時(shí)間內(nèi),服務(wù)器端總是主動(dòng)拆除我們的連接嗎?
            不管怎么樣,我們必須防止類似情況再度發(fā)生!
            首先,我們要防止不斷開辟新的端口,這可以通過設(shè)置SO_REUSEADDR套接字選項(xiàng)做到:
            重用本地地址和端口
            以前我總是一個(gè)端口不行,就換一個(gè)新的使用,所以導(dǎo)致讓數(shù)千個(gè)端口進(jìn)入CLOSE_WAIT狀態(tài)。如果下次還發(fā)生這種尷尬狀況,我希望加一個(gè)限定,只是當(dāng)前這個(gè)端口處于CLOSE_WAIT狀態(tài)!
            在調(diào)用
            sockConnected = socket(AF_INET, SOCK_STREAM, 0);
            之后,我們要設(shè)置該套接字的選項(xiàng)來重用:
            /// 允許重用本地地址和端口:
            /// 這樣的好處是,即使socket斷了,調(diào)用前面的socket函數(shù)也不會(huì)占用另一個(gè),而是始終就是一個(gè)端口
            /// 這樣防止socket始終連接不上,那么按照原來的做法,會(huì)不斷地?fù)Q端口。
            int nREUSEADDR = 1;
            setsockopt(sockConnected,
                          SOL_SOCKET,
                          SO_REUSEADDR,
                          (const char*)&nREUSEADDR,
                          sizeof(int));

            教科書上是這么說的:這樣,假如服務(wù)器關(guān)閉或者退出,造成本地地址和端口都處于TIME_WAIT狀態(tài),那么SO_REUSEADDR就顯得非常有用。
            也許我們無法避免被凍結(jié)在CLOSE_WAIT狀態(tài)永遠(yuǎn)不出現(xiàn),但起碼可以保證不會(huì)占用新的端口。
            其次,我們要設(shè)置SO_LINGER套接字選項(xiàng):(相關(guān)介紹可參考:SO_LINGER 選項(xiàng)設(shè)置)
            從容關(guān)閉還是強(qiáng)行關(guān)閉?
            LINGER是“拖延”的意思。
            默認(rèn)情況下(Win2k),SO_DONTLINGER套接字選項(xiàng)的是1;SO_LINGER選項(xiàng)是,linger為{l_onoff:0,l_linger:0}。
            如果在發(fā)送數(shù)據(jù)的過程中(send()沒有完成,還有數(shù)據(jù)沒發(fā)送)而調(diào)用了closesocket(),以前我們一般采取的措施是“從容關(guān)閉”:
            因?yàn)樵谕顺龇?wù)或者每次重新建立socket之前,我都會(huì)先調(diào)用
            /// 先將雙向的通訊關(guān)閉
                 shutdown(sockConnected, SD_BOTH);
                 /// 安全起見,每次建立Socket連接前,先把這個(gè)舊連接關(guān)閉
            closesocket(sockConnected);
            我們這次要這么做:
            設(shè)置SO_LINGER為零(亦即linger結(jié)構(gòu)中的l_onoff域設(shè)為非零,但l_linger為0),便不用擔(dān)心closesocket調(diào)用進(jìn)入“鎖定”狀態(tài)(等待完成),不論是否有排隊(duì)數(shù)據(jù)未發(fā)送或未被確認(rèn)。這種關(guān)閉方式稱為“強(qiáng)行關(guān)閉”,因?yàn)樘捉幼值奶撾娐妨⒓幢粡?fù)位,尚未發(fā)出的所有數(shù)據(jù)都會(huì)丟失。在遠(yuǎn)端的recv()調(diào)用都會(huì)失敗,并返回WSAECONNRESET錯(cuò)誤。
            在connect成功建立連接之后設(shè)置該選項(xiàng):
            linger m_sLinger;
            m_sLinger.l_onoff = 1; // (在closesocket()調(diào)用,但是還有數(shù)據(jù)沒發(fā)送完畢的時(shí)候容許逗留)
            m_sLinger.l_linger = 0; // (容許逗留的時(shí)間為0秒)
            setsockopt(sockConnected,
                     SOL_SOCKET,
                     SO_LINGER,
                     (const char*)&m_sLinger,
                     sizeof(linger));

            總結(jié)
            也許我們避免不了CLOSE_WAIT狀態(tài)凍結(jié)的再次出現(xiàn),但我們會(huì)使影響降到最小,希望那個(gè)重用套接字選項(xiàng)能夠使得下一次重新建立連接時(shí)可以把CLOSE_WAIT狀態(tài)踢掉。


            本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/factor2000/archive/2009/02/23/3929197.aspx

            posted on 2011-05-01 15:55 厚積薄發(fā) 閱讀(725) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)編程

            導(dǎo)航

            <2025年6月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            統(tǒng)計(jì)

            常用鏈接

            留言簿

            隨筆分類

            文章分類

            文章檔案

            搜索

            最新評(píng)論

            亚洲午夜福利精品久久| 久久亚洲中文字幕精品有坂深雪| 成人国内精品久久久久影院| 久久久久综合网久久| 国内精品久久久久久久久| 少妇久久久久久被弄到高潮 | 久久艹国产| 亚洲国产成人精品91久久久 | 97久久精品无码一区二区天美| 久久国产精品无码一区二区三区 | 久久国产精品一区| 一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 久久精品国产久精国产一老狼| 2020最新久久久视精品爱| 一本色综合网久久| 色综合久久久久综合99| 国产成人精品久久二区二区| 久久最新免费视频| 青青草原综合久久| 久久久久亚洲av无码专区| 久久久这里有精品| 久久亚洲国产成人精品无码区| 精品久久久久久久久午夜福利| 久久久久久久97| 亚洲国产成人乱码精品女人久久久不卡 | 久久国产香蕉视频| 国产精品99久久不卡| 久久人人爽爽爽人久久久| 亚洲中文久久精品无码ww16| 久久综合狠狠综合久久97色| 一本大道久久a久久精品综合| 国产成人精品白浆久久69| 亚洲AV日韩精品久久久久久久| 偷窥少妇久久久久久久久| 亚洲精品tv久久久久久久久久| 久久99精品免费一区二区| 亚洲国产成人久久精品动漫| 久久精品这里热有精品| 亚洲一本综合久久| 国产ww久久久久久久久久| 精品水蜜桃久久久久久久|