• <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狀態的說明

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


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

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

            總結
            也許我們避免不了CLOSE_WAIT狀態凍結的再次出現,但我們會使影響降到最小,希望那個重用套接字選項能夠使得下一次重新建立連接時可以把CLOSE_WAIT狀態踢掉。


            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/factor2000/archive/2009/02/23/3929197.aspx

            posted on 2011-05-01 15:55 厚積薄發 閱讀(717) 評論(0)  編輯 收藏 引用 所屬分類: 網絡編程

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿

            隨筆分類

            文章分類

            文章檔案

            搜索

            最新評論

            一本大道加勒比久久综合| 久久精品国产99国产精品导航| 99久久人妻无码精品系列| 久久精品无码专区免费东京热 | 久久精品国产91久久麻豆自制| 久久精品一区二区三区不卡| 国产精品成人99久久久久 | 青草久久久国产线免观| 少妇无套内谢久久久久| 国内精品久久人妻互换| 日本精品久久久久久久久免费| 欧美牲交A欧牲交aⅴ久久| 99久久免费国产精品| 亚洲伊人久久大香线蕉综合图片| 99久久这里只有精品| 久久亚洲AV成人无码| 国产精自产拍久久久久久蜜| 国产A级毛片久久久精品毛片| 久久国产精品久久久| 麻豆亚洲AV永久无码精品久久| 国产精品VIDEOSSEX久久发布| 麻豆亚洲AV永久无码精品久久| 香蕉aa三级久久毛片| 国产精品免费久久久久久久久 | 久久亚洲高清综合| 欧美精品一本久久男人的天堂| 亚洲精品无码久久久久sm| 亚洲国产视频久久| 青青草国产97免久久费观看| 久久精品无码一区二区三区免费| 色欲av伊人久久大香线蕉影院| 2021最新久久久视精品爱 | 久久人人妻人人爽人人爽| 伊人久久大香线蕉精品不卡| 久久毛片免费看一区二区三区| 亚洲成色999久久网站| 国产国产成人精品久久| 69SEX久久精品国产麻豆| 日日噜噜夜夜狠狠久久丁香五月 | 久久人人爽爽爽人久久久| 久久精品亚洲一区二区三区浴池|