• <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>
            面對現(xiàn)實(shí),超越自己
            逆水行舟,不進(jìn)則退
            posts - 269,comments - 32,trackbacks - 0

            Author : Kevin Lynx

            主要部分,四次握手:

            斷開連接其實(shí)從我的角度看不區(qū)分客戶端和服務(wù)器端,任何一方都可以調(diào)用close(or closesocket)之類
            的函數(shù)開始主動終止一個(gè)連接。這里先暫時(shí)說正常情況。當(dāng)調(diào)用close函數(shù)斷開一個(gè)連接時(shí),主動斷開的
            一方發(fā)送FIN(finish報(bào)文給對方。有了之前的經(jīng)驗(yàn),我想你應(yīng)該明白我說的FIN報(bào)文時(shí)什么東西。也就是
            一個(gè)設(shè)置了FIN標(biāo)志位的報(bào)文段。FIN報(bào)文也可能附加用戶數(shù)據(jù),如果這一方還有數(shù)據(jù)要發(fā)送時(shí),將數(shù)據(jù)附
            加到這個(gè)FIN報(bào)文時(shí)完全正常的。之后你會看到,這種附加報(bào)文還會有很多,例如ACK報(bào)文。我們所要把握
            的原則是,TCP肯定會力所能及地達(dá)到最大效率,所以你能夠想到的優(yōu)化方法,我想TCP都會想到。

            當(dāng)被動關(guān)閉的一方收到FIN報(bào)文時(shí),它會發(fā)送ACK確認(rèn)報(bào)文(對于ACK這個(gè)東西你應(yīng)該很熟悉了)。這里有個(gè)
            東西要注意,因?yàn)門CP是雙工的,也就是說,你可以想象一對TCP連接上有兩條數(shù)據(jù)通路。當(dāng)發(fā)送FIN報(bào)文
            時(shí),意思是說,發(fā)送FIN的一端就不能發(fā)送數(shù)據(jù),也就是關(guān)閉了其中一條數(shù)據(jù)通路。被動關(guān)閉的一端發(fā)送
            了ACK后,應(yīng)用層通常就會檢測到這個(gè)連接即將斷開,然后被動斷開的應(yīng)用層調(diào)用close關(guān)閉連接。

            我可以告訴你,一旦當(dāng)你調(diào)用close(or closesocket),這一端就會發(fā)送FIN報(bào)文。也就是說,現(xiàn)在被動
            關(guān)閉的一端也發(fā)送FIN給主動關(guān)閉端。有時(shí)候,被動關(guān)閉端會將ACK和FIN兩個(gè)報(bào)文合在一起發(fā)送。主動
            關(guān)閉端收到FIN后也發(fā)送ACK,然后整個(gè)連接關(guān)閉(事實(shí)上還沒完全關(guān)閉,只是關(guān)閉需要交換的報(bào)文發(fā)送
            完畢),四次握手完成。如你所見,因?yàn)楸粍雨P(guān)閉端可能會將ACK和FIN合到一起發(fā)送,所以這也算不上
            嚴(yán)格的四次握手---四個(gè)報(bào)文段。

            在前面的文章中,我一直沒提TCP的狀態(tài)轉(zhuǎn)換。在這里我還是在猶豫是不是該將那張四處通用的圖拿出來,
            不過,這里我只給出斷開連接時(shí)的狀態(tài)轉(zhuǎn)換圖,摘自<The TCP/IP Guide>:

             

            給出一個(gè)正常關(guān)閉時(shí)的windump信息:

            14:00:38.819856 IP cd-zhangmin.1748 > 220.181.37.55.80: F 1:1(0) ack 1 win 65535
            14:00:38.863989 IP 220.181.37.55.80 > cd-zhangmin.1748: F 1:1(0) ack 2 win 2920
            14:00:38.864412 IP cd-zhangmin.1748 > 220.181.37.55.80: . ack 2 win 65535 

             

            補(bǔ)充細(xì)節(jié):

            關(guān)于以上的四次握手,我補(bǔ)充下細(xì)節(jié):
            1. 默認(rèn)情況下(不改變socket選項(xiàng)),當(dāng)你調(diào)用close( or closesocket,以下說close不再重復(fù))時(shí),如果
            發(fā)送緩沖中還有數(shù)據(jù),TCP會繼續(xù)把數(shù)據(jù)發(fā)送完。
            2. 發(fā)送了FIN只是表示這端不能繼續(xù)發(fā)送數(shù)據(jù)(應(yīng)用層不能再調(diào)用send發(fā)送),但是還可以接收數(shù)據(jù)。
            3. 應(yīng)用層如何知道對端關(guān)閉?通常,在最簡單的阻塞模型中,當(dāng)你調(diào)用recv時(shí),如果返回0,則表示對端
            關(guān)閉。在這個(gè)時(shí)候通常的做法就是也調(diào)用close,那么TCP層就發(fā)送FIN,繼續(xù)完成四次握手。如果你不調(diào)用
            close,那么對端就會處于FIN_WAIT_2狀態(tài),而本端則會處于CLOSE_WAIT狀態(tài)。這個(gè)可以寫代碼試試。
            4. 在很多時(shí)候,TCP連接的斷開都會由TCP層自動進(jìn)行,例如你CTRL+C終止你的程序,TCP連接依然會正常關(guān)
            閉,你可以寫代碼試試。

            特別的TIME_WAIT狀態(tài):

            從以上TCP連接關(guān)閉的狀態(tài)轉(zhuǎn)換圖可以看出,主動關(guān)閉的一方在發(fā)送完對對方FIN報(bào)文的確認(rèn)(ACK)報(bào)文后,
            會進(jìn)入TIME_WAIT狀態(tài)。TIME_WAIT狀態(tài)也稱為2MSL狀態(tài)。

            什么是2MSL?MSL即Maximum Segment Lifetime,也就是報(bào)文最大生存時(shí)間,引用<TCP/IP詳解>中的話:“
            它(MSL)是任何報(bào)文段被丟棄前在網(wǎng)絡(luò)內(nèi)的最長時(shí)間。”那么,2MSL也就是這個(gè)時(shí)間的2倍。其實(shí)我覺得沒
            必要把這個(gè)MSL的確切含義搞明白,你所需要明白的是,當(dāng)TCP連接完成四個(gè)報(bào)文段的交換時(shí),主動關(guān)閉的
            一方將繼續(xù)等待一定時(shí)間(2-4分鐘),即使兩端的應(yīng)用程序結(jié)束。你可以寫代碼試試,然后用netstat查看下。

            為什么需要2MSL?根據(jù)<TCP/IP詳解>和<The TCP/IP Guide>中的說法,有兩個(gè)原因:
            其一,保證發(fā)送的ACK會成功發(fā)送到對方,如何保證?我覺得可能是通過超時(shí)計(jì)時(shí)器發(fā)送。這個(gè)就很難用
            代碼演示了。
            其二,報(bào)文可能會被混淆,意思是說,其他時(shí)候的連接可能會被當(dāng)作本次的連接。直接引用<The TCP/IP Guide>
            的說法:The second is to provide a “buffering period” between the end of this connection
            and any subsequent ones. If not for this period, it is possible that packets from different
            connections could be mixed, creating confusion.

            TIME_WAIT狀態(tài)所帶來的影響:

            當(dāng)某個(gè)連接的一端處于TIME_WAIT狀態(tài)時(shí),該連接將不能再被使用。事實(shí)上,對于我們比較有現(xiàn)實(shí)意義的
            是,這個(gè)端口將不能再被使用。某個(gè)端口處于TIME_WAIT狀態(tài)(其實(shí)應(yīng)該是這個(gè)連接)時(shí),這意味著這個(gè)TCP
            連接并沒有斷開(完全斷開),那么,如果你bind這個(gè)端口,就會失敗。

            對于服務(wù)器而言,如果服務(wù)器突然crash掉了,那么它將無法再2MSL內(nèi)重新啟動,因?yàn)閎ind會失敗。解決這
            個(gè)問題的一個(gè)方法就是設(shè)置socket的SO_REUSEADDR選項(xiàng)。這個(gè)選項(xiàng)意味著你可以重用一個(gè)地址。

            對于TIME_WAIT的插曲:

            當(dāng)建立一個(gè)TCP連接時(shí),服務(wù)器端會繼續(xù)用原有端口監(jiān)聽,同時(shí)用這個(gè)端口與客戶端通信。而客戶端默認(rèn)情況
            下會使用一個(gè)隨機(jī)端口與服務(wù)器端的監(jiān)聽端口通信。有時(shí)候,為了服務(wù)器端的安全性,我們需要對客戶端進(jìn)行
            驗(yàn)證,即限定某個(gè)IP某個(gè)特定端口的客戶端。客戶端可以使用bind來使用特定的端口。

            對于服務(wù)器端,當(dāng)設(shè)置了SO_REUSEADDR選項(xiàng)時(shí),它可以在2MSL內(nèi)啟動并listen成功。但是對于客戶端,當(dāng)使
            用bind并設(shè)置SO_REUSEADDR時(shí),如果在2MSL內(nèi)啟動,雖然bind會成功,但是在windows平臺上connect會失敗。
            而在linux上則不存在這個(gè)問題。(我的實(shí)驗(yàn)平臺:winxp, ubuntu7.10)

            要解決windows平臺的這個(gè)問題,可以設(shè)置SO_LINGER選項(xiàng)。SO_LINGER選項(xiàng)決定調(diào)用close時(shí),TCP的行為。
            SO_LINGER涉及到linger結(jié)構(gòu)體,如果設(shè)置結(jié)構(gòu)體中l(wèi)_onoff為非0,l_linger為0,那么調(diào)用close時(shí)TCP連接
            會立刻斷開,TCP不會將發(fā)送緩沖中未發(fā)送的數(shù)據(jù)發(fā)送,而是立即發(fā)送一個(gè)RST報(bào)文給對方,這個(gè)時(shí)候TCP連
            接就不會進(jìn)入TIME_WAIT狀態(tài)。

            如你所見,這樣做雖然解決了問題,但是并不安全。通過以上方式設(shè)置SO_LINGER狀態(tài),等同于設(shè)置SO_DONTLINGER
            狀態(tài)。

            斷開連接時(shí)的意外:
            這個(gè)算不上斷開連接時(shí)的意外,當(dāng)TCP連接發(fā)生一些物理上的意外情況時(shí),例如網(wǎng)線斷開,linux上的TCP實(shí)現(xiàn)
            會依然認(rèn)為該連接有效,而windows則會在一定時(shí)間后返回錯(cuò)誤信息。

            這似乎可以通過設(shè)置SO_KEEPALIVE選項(xiàng)來解決,不過不知道這個(gè)選項(xiàng)是否對于所有平臺都有效。

            總結(jié):

            個(gè)人感覺,越寫越爛。接下來會講到TCP的數(shù)據(jù)發(fā)送,這會涉及到滑動窗口各種定時(shí)器之類的東西。我真誠
            希望各位能夠多提意見。對于TCP連接的斷開,我們只要清楚:
            1. 在默認(rèn)情況下,調(diào)用close時(shí)TCP會繼續(xù)將數(shù)據(jù)發(fā)送完畢;
            2. TIME_WAIT狀態(tài)會導(dǎo)致的問題;
            3. 連接意外斷開時(shí)可能會出現(xiàn)的問題。
            4. maybe more...

            本文轉(zhuǎn)自:http://www.shnenglu.com/kevinlynx/archive/2008/05/14/49825.html

            posted on 2012-09-20 13:00 王海光 閱讀(515) 評論(0)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)編程
            亚洲国产精品成人久久| 91久久精品电影| 久久99久久成人免费播放| 久久丫精品国产亚洲av不卡| 中文字幕精品无码久久久久久3D日动漫 | 四虎久久影院| 欧美日韩精品久久久久 | 国内精品久久久久影院一蜜桃 | 久久人妻AV中文字幕| 国产精品一区二区久久精品涩爱 | 国产69精品久久久久99| 国产福利电影一区二区三区久久久久成人精品综合| 久久久久久无码Av成人影院| 久久99精品久久只有精品| 久久精品国产第一区二区三区 | 精品久久人妻av中文字幕| 久久国产精品无码一区二区三区| 久久精品人成免费| 国产成人精品综合久久久| 久久99国产精品久久99小说| 亚洲狠狠婷婷综合久久蜜芽| 97久久久精品综合88久久| 99国内精品久久久久久久| 怡红院日本一道日本久久| 久久久久亚洲?V成人无码| 日产精品久久久久久久| 91精品国产综合久久精品| 久久免费大片| 精品人妻久久久久久888| 久久久精品久久久久特色影视| 人妻无码αv中文字幕久久琪琪布 人妻无码精品久久亚瑟影视 | 久久无码人妻一区二区三区 | 久久一本综合| 久久久亚洲欧洲日产国码aⅴ| 久久精品男人影院| 久久91精品国产91久| 伊人色综合久久天天| 精品多毛少妇人妻AV免费久久| 国内精品久久久久久99| 久久久久久无码国产精品中文字幕| 久久久久亚洲av综合波多野结衣|