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

            Prayer

            在一般中尋求卓越
            posts - 1256, comments - 190, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            CLOSE_WAIT狀態(tài)的生成原因
            首先我們知道,如果我們的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就置為L(zhǎng)AST_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)閉己方連接前有那么多事情要做嗎?

            elssann舉例說,當(dāng)對(duì)方調(diào)用closesocket的時(shí)候,我的程序正在調(diào)用recv中,這時(shí)候有可能對(duì)方發(fā)送的FIN包我沒有收到,而是由TCP代回了一個(gè)ACK包,所以我這邊套接字進(jìn)入CLOSE_WAIT狀態(tài)。

            所以他建議在這里判斷recv函數(shù)的返回值是否已出錯(cuò),是的話就主動(dòng)closesocket,這樣防止沒有接收到FIN包。

            因?yàn)榍懊嫖覀円呀?jīng)設(shè)置了recv超時(shí)時(shí)間為30秒,那么如果真的是超時(shí)了,這里收到的錯(cuò)誤應(yīng)該是WSAETIMEDOUT,這種情況下也可以主動(dòng)關(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)閉還是強(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)踢掉。


            我的意思是:當(dāng)一方關(guān)閉連接后,另外一方?jīng)]有檢測(cè)到,就導(dǎo)致了CLOSE_WAIT的出現(xiàn),上次我的一個(gè)朋友也是這樣,他寫了一個(gè)客戶端和 APACHE連接,當(dāng)APACHE把連接斷掉后,他沒檢測(cè)到,出現(xiàn)了CLOSE_WAIT,后來我叫他檢測(cè)了這個(gè)地方,他添加了調(diào)用 closesocket的代碼后,這個(gè)問題就消除了。
            如果你在關(guān)閉連接前還是出現(xiàn)CLOSE_WAIT,建議你取消shutdown的調(diào)用,直接兩邊closesocket試試。


            另外一個(gè)問題:

            比如這樣的一個(gè)例子:
            當(dāng)客戶端登錄上服務(wù)器后,發(fā)送身份驗(yàn)證的請(qǐng)求,服務(wù)器收到了數(shù)據(jù),對(duì)客戶端身份進(jìn)行驗(yàn)證,發(fā)現(xiàn)密碼錯(cuò)誤,這時(shí)候服務(wù)器的一般做法應(yīng)該是先發(fā)送一個(gè)密碼錯(cuò)誤的信息給客戶端,然后把連接斷掉。

            如果把
            m_sLinger.l_onoff = 1;
            m_sLinger.l_linger = 0;
            這樣設(shè)置后,很多情況下,客戶端根本就收不到密碼錯(cuò)誤的消息,連接就被斷了。

             


            出現(xiàn)CLOSE_WAIT的原因很簡(jiǎn)單,就是某一方在網(wǎng)絡(luò)連接斷開后,沒有檢測(cè)到這個(gè)錯(cuò)誤,沒有執(zhí)行closesocket,導(dǎo)致了這個(gè)狀態(tài)的實(shí)現(xiàn),這在TCP/IP協(xié)議的狀態(tài)變遷圖上可以清楚看到。同時(shí)和這個(gè)相對(duì)應(yīng)的還有一種叫TIME_WAIT的。

            另外,把SOCKET的SO_LINGER設(shè)置為0秒拖延(也就是立即關(guān)閉)在很多時(shí)候是有害處的。
            還有,把端口設(shè)置為可復(fù)用是一種不安全的網(wǎng)絡(luò)編程方法。

            2021久久精品国产99国产精品| 999久久久国产精品| 日日狠狠久久偷偷色综合0| 久久综合久久久| 久久精品国产秦先生| 四虎国产精品免费久久久| 久久精品国产69国产精品亚洲 | 久久精品国产第一区二区三区| 日韩精品久久久久久久电影| 亚洲国产成人久久精品99 | 无码精品久久久久久人妻中字 | 一级做a爰片久久毛片人呢| 久久久青草久久久青草| 国产成人久久久精品二区三区| 欧美激情精品久久久久| 久久激情亚洲精品无码?V| 久久久99精品成人片中文字幕 | 久久亚洲sm情趣捆绑调教| 四虎国产精品成人免费久久| 伊人久久无码中文字幕| 国产亚洲欧美成人久久片| 青青草国产精品久久久久| 欧美激情精品久久久久久久| 97精品依人久久久大香线蕉97| 国产精品国色综合久久| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 国产成人无码久久久精品一| 91麻豆精品国产91久久久久久 | 久久www免费人成看国产片| 天天影视色香欲综合久久| 亚洲女久久久噜噜噜熟女| 亚洲成色999久久网站| 2021国产精品午夜久久| a级成人毛片久久| 伊人色综合久久天天人守人婷| 久久国产欧美日韩精品| 欧美午夜A∨大片久久 | 亚洲中文字幕久久精品无码APP| av无码久久久久不卡免费网站 | 99久久精品免费看国产免费| 色偷偷88欧美精品久久久|