拒絕八股文,透過(guò)實(shí)戰(zhàn)理解TCP連接過(guò)程

一、準(zhǔn)備工作

1.1 Wireshark

下載安裝(MAC版)

Wireshark(前稱(chēng)Ethereal)是一個(gè)網(wǎng)絡(luò)封包分析軟件瘫里。網(wǎng)絡(luò)封包分析軟件的功能是截取網(wǎng)絡(luò)封包,并盡可能顯示出最為詳細(xì)的網(wǎng)絡(luò)封包資料荡碾。Wireshark使用WinPCAP作為接口谨读,直接與網(wǎng)卡進(jìn)行數(shù)據(jù)報(bào)文交換。 -- 摘自百度百科

官網(wǎng)地址:https://www.wireshark.org/
mac版本下載地址:https://2.na.dl.wireshark.org/osx/Wireshark%203.4.9%20Intel%2064.dmg

配置啟動(dòng)

第一次下載完之后坛吁,打開(kāi)可能會(huì)碰到如下提示:
you don't have permission to capture on that device

解決方式:

whoami
cd /dev
sudo chown ${whoami}:admin bp*

執(zhí)行完上述命令重新啟動(dòng)工具即可劳殖。

1.2 netstat

Netstat是控制臺(tái)命令,是一個(gè)監(jiān)控TCP/IP網(wǎng)絡(luò)的非常有用的工具,它可以顯示路由表拨脉、實(shí)際的網(wǎng)絡(luò)連接以及每一個(gè)網(wǎng)絡(luò)接口設(shè)備的狀態(tài)信息哆姻。Netstat用于顯示與IP、TCP玫膀、UDP和ICMP協(xié)議相關(guān)的統(tǒng)計(jì)數(shù)據(jù)矛缨,一般用于檢驗(yàn)本機(jī)各端口的網(wǎng)絡(luò)連接情況。 -- 摘自百度百科

這個(gè)簡(jiǎn)單掌握一些命令參數(shù)就好

1.3 Java&IDE

這個(gè)玩意相信不用多說(shuō)帖旨,這里只需要copy一些后面會(huì)用到的代碼即可

這個(gè)程序大概就是監(jiān)聽(tīng)指定端口箕昭,當(dāng)有新的連接到來(lái)分配一個(gè)線程處理該socket的其他事件

public class BIOServer {
    private final static ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    private static void handleSocket(Socket socket) throws IOException {
        byte[] socketContent = new byte[1024];
        int len;
        while ((len = socket.getInputStream().read(socketContent)) != -1) {
            System.out.println(
                "Thread:" + Thread.currentThread().getName() + " receive message:" + new String(socketContent, 0, len));
        }
    }

    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(8888);
        while (true) {
            Socket socket = serverSocket.accept(); // 此處將阻塞直到連接建立
            EXECUTOR_SERVICE.submit(() -> {
                System.out.println("New connection!,Submit it to thread:" + Thread.currentThread().getName());
                try {
                    handleSocket(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }

    }
}

二、前景知識(shí)準(zhǔn)備

在查看TCP連接報(bào)文時(shí)解阅,主要看的就是TCP頭部信息落竹,所以這里先貼一下TCP頭部結(jié)構(gòu),有個(gè)感覺(jué):


image.png

2.2 TCP連接狀態(tài)一覽

整個(gè)TCP的連接和斷開(kāi)其實(shí)也是TCP狀態(tài)的變化货抄,所以提前了解下TCP狀態(tài)都有哪些筋量,更加有助于后面的分析。

狀態(tài) 描述
LISTEN 表示服務(wù)器端的某個(gè)SOCKET處于監(jiān)聽(tīng)狀態(tài)碉熄,等待客戶(hù)端的連接
SYN-SENT 客戶(hù)端發(fā)送syn請(qǐng)求連接服務(wù)器端時(shí)的狀態(tài)
SYN-RECEIVED 服務(wù)器端收到客戶(hù)端的請(qǐng)求連接syn報(bào)文時(shí)處于的狀態(tài)
ESTABLISHED TCP連接建立成功時(shí)的狀態(tài)
FIN-WAIT-1 當(dāng)客戶(hù)端向服務(wù)端發(fā)起斷開(kāi)連接FIN報(bào)文后,進(jìn)入此狀態(tài)肋拔,等待服務(wù)端ACK確認(rèn)
FIN-WAIT-2 當(dāng)客戶(hù)端收到服務(wù)端對(duì)FIN報(bào)文的ACK后锈津,進(jìn)入此狀態(tài)。此時(shí)該連接為半連接凉蜂,如果被動(dòng)關(guān)閉方一直不進(jìn)行關(guān)閉琼梆,那么該客戶(hù)端socket將一直保持該狀態(tài)
CLOSE-WAIT 當(dāng)服務(wù)端確認(rèn)了客戶(hù)端的FIN關(guān)閉報(bào)文之后進(jìn)入此狀態(tài);此時(shí)服務(wù)端 可能有一些數(shù)據(jù)需要處理
LAST-ACK 當(dāng)被動(dòng)關(guān)閉方發(fā)送FIN關(guān)閉報(bào)文之后窿吩,就進(jìn)入該狀態(tài)等待最終客戶(hù)端的ACK確認(rèn)
TIME-WAIT 當(dāng)主動(dòng)關(guān)閉方收到被動(dòng)關(guān)閉方的FIN關(guān)閉報(bào)文并進(jìn)行ACK確認(rèn)之后茎杂,主動(dòng)方會(huì)進(jìn)入此狀態(tài),并且等待2MSL
CLOSED 關(guān)閉狀態(tài)
圖源:https://www.cnblogs.com/qingergege/p/6603488.html

三纫雁、實(shí)戰(zhàn)TCP連接的三次握手

客戶(hù)端--> telnet
服務(wù)端--> java程序

首先直接來(lái)看三次握手的整個(gè)流程:


TCP連接三次握手

接下來(lái)自上往下分析整個(gè)連接建立的過(guò)程煌往。

3.1 服務(wù)端創(chuàng)建并監(jiān)聽(tīng)socket

首先啟動(dòng)1.3節(jié)的java程序,通過(guò)netstat查看服務(wù)端socket狀態(tài):

netstat -a -n | grep 8888

image.png

可以看到服務(wù)端程序啟動(dòng)之后,這里socket狀態(tài)為LISTEN刽脖,正在等待新連接與其建立連接羞海。

3.2 客戶(hù)端連接服務(wù)端socket

執(zhí)行命令

telnet 127.0.0.1 8888

然后觀察Wireshark得到如下報(bào)文:


image.png

上面圈出來(lái)的三條報(bào)文就是TCP三次握手的過(guò)程了,接下來(lái)分別看一下這三條報(bào)文曲管,首先第一條


image.png

通過(guò)這里src port和dst port可以得知却邓,這是客戶(hù)端發(fā)向服務(wù)端的一條報(bào)文,這條報(bào)文帶有SYN(即SYN=1)標(biāo)志位院水,表示請(qǐng)求建立連接腊徙,那么此時(shí)客戶(hù)端的狀態(tài)應(yīng)該變?yōu)榱?strong>SYN_SEND;不過(guò)由于服務(wù)端馬上進(jìn)行ACK檬某,這個(gè)狀態(tài)捕捉不到撬腾,然后查看第二條報(bào)文:

image.png

相同,通過(guò)這里src port和dst port可以得知橙喘,這是服務(wù)度發(fā)向客戶(hù)端的一條報(bào)文时鸵,這條報(bào)文中帶有SYN和ACK標(biāo)志位,代表了服務(wù)端對(duì)客戶(hù)端請(qǐng)求的確認(rèn)厅瞎,此時(shí)并且還回復(fù)了ack=1,這里ack的值為客戶(hù)端發(fā)向服務(wù)端的報(bào)文中攜帶的Seq值+1饰潜,用于確認(rèn)服務(wù)端收到了此條報(bào)文,seq機(jī)制也是TCP實(shí)現(xiàn)報(bào)文丟失重傳從而可靠的重點(diǎn)和簸。再來(lái)看第三條報(bào)文:
image.png

同理得知這條報(bào)文是客戶(hù)端發(fā)給服務(wù)端的報(bào)文彭雾,攜帶標(biāo)志位ACK,并且回復(fù)ack=y+1,這里的y就是第二條報(bào)文中服務(wù)端發(fā)向客戶(hù)端報(bào)文攜帶的seq序列锁保。到這里TCP三次握手完畢了薯酝,接下來(lái)通過(guò)netstat查看socket狀態(tài):

netstat -a -n | grep 8888
image.png

可以看到此時(shí)客戶(hù)端的socket和服務(wù)端socket狀態(tài)都變?yōu)榱薊STABLISHED,此時(shí)我們通過(guò)客戶(hù)端和服務(wù)端進(jìn)行通信


image.png
image.png

四爽柒、實(shí)戰(zhàn)TCP連接的四次揮手

客戶(hù)端--> telnet
服務(wù)端--> java程序

image.png

4.1 關(guān)閉客戶(hù)端

當(dāng)關(guān)閉客戶(hù)端時(shí)吴菠,則客戶(hù)端會(huì)向服務(wù)端發(fā)起斷開(kāi)請(qǐng)求,服務(wù)端收到斷開(kāi)請(qǐng)求浩村,回應(yīng)客戶(hù)端:


image.png

此時(shí)查看客戶(hù)端和服務(wù)端socket狀態(tài):


image.png

可以看到客戶(hù)端socket此時(shí)因?yàn)橐呀?jīng)收到了服務(wù)端的ack做葵,所以此時(shí)狀態(tài)為FIN_WAIT_2,并且服務(wù)端socket狀態(tài)變?yōu)镃LOSE_WAIT

4.2 關(guān)閉服務(wù)端

關(guān)閉了客戶(hù)端之后心墅,再來(lái)關(guān)閉服務(wù)端進(jìn)行觀察

image.png

目前只剩下客戶(hù)端一個(gè)socket了酿矢,說(shuō)明服務(wù)端socket已經(jīng)完成了關(guān)閉,此時(shí)客戶(hù)端處于TIME_WAIT階段怎燥,需要等待2MSL之后才可以完成關(guān)閉瘫筐。

到這里差不多結(jié)束了,可能你會(huì)問(wèn)铐姚,在第二節(jié)中列了那么多狀態(tài)策肝,怎么沒(méi)看到其他狀態(tài)呢?這是因?yàn)橛行顟B(tài)存在時(shí)間過(guò)短導(dǎo)致無(wú)法捕捉到,比如為什么沒(méi)看到SYN_SEND驳糯,那是因?yàn)楫?dāng)客戶(hù)端發(fā)送SYN報(bào)文后篇梭,服務(wù)端馬上就進(jìn)行了確認(rèn),并且客戶(hù)端也馬上對(duì)服務(wù)端的確認(rèn)進(jìn)行了確認(rèn)酝枢,所以這些中間狀態(tài)很難捕捉恬偷。

五、TCP連接過(guò)程中的一些注意點(diǎn)

5.1 三次握手時(shí)

5.1.1 注意點(diǎn)一

為什么連接時(shí)只需要三次就夠了帘睦,兩次可以嗎袍患?四次可以嗎?

  • 假如握手兩次

這種情況下竣付,就相當(dāng)于客戶(hù)端發(fā)送syn連接請(qǐng)求诡延,服務(wù)端進(jìn)行確認(rèn),然后連接建立成功古胆,總共兩次肆良。這樣有沒(méi)有問(wèn)題呢?我們假如在客戶(hù)端第一次發(fā)送syn連接請(qǐng)求時(shí)逸绎,由于網(wǎng)絡(luò)擁塞等原因惹恃,服務(wù)端遲遲沒(méi)有做出ACK應(yīng)答,那么此時(shí)客戶(hù)端就認(rèn)為第一次發(fā)送的syn請(qǐng)求失效棺牧,然后重發(fā)一個(gè)新的syn連接請(qǐng)求巫糙,然后建立成功,緊接著啪啪啪通訊完畢颊乘,然后啪啪啪連接斷開(kāi)参淹,看似沒(méi)有什么問(wèn)題了,但是假如最早發(fā)送的syn請(qǐng)求并非失效乏悄,只是網(wǎng)絡(luò)等原因?qū)е略撜?qǐng)求滯留浙值,正好此時(shí)該請(qǐng)求報(bào)文到達(dá)服務(wù)端,服務(wù)端收到連接請(qǐng)求建立連接成功(因?yàn)榫蛢纱伍菪。源藭r(shí)連接已經(jīng)建立了)开呐,然后等待客戶(hù)端發(fā)送數(shù)據(jù),但是其實(shí)客戶(hù)端早啪啪啪結(jié)束回家了识啦,此時(shí)服務(wù)端就只能干等著白白消耗資源!

  • 假如握手四次

四次無(wú)非就是和四次揮手一樣神妹,那么多的一步多到哪里了颓哮?從三次揮手過(guò)程可以看到,在客戶(hù)端發(fā)送syn請(qǐng)求之后鸵荠,客戶(hù)端同時(shí)發(fā)給客戶(hù)端syn連接請(qǐng)求冕茅,以及對(duì)客戶(hù)端syn的ack確認(rèn),這兩步能分開(kāi)不?分開(kāi)倒也是可以姨伤,但是能一步解決為啥要分兩步哨坪?吃飽了撐的嗎不是!

5.2 四次揮手時(shí)

5.2.1 注意點(diǎn)一

為什么當(dāng)服務(wù)端發(fā)送FIN確認(rèn)斷開(kāi)后乍楚,客戶(hù)端不立馬close当编,而是進(jìn)入TIME_WAIT狀態(tài),等待2MSL之后才斷開(kāi)徒溪?

MSL(Max Segment Lifetime忿偷,最大分段生存期,指一個(gè)TCP報(bào)文在Internet上的最長(zhǎng)生存時(shí)間)

回顧一下TCP連接斷開(kāi)的過(guò)程:
1)客戶(hù)端發(fā)送FIN
2)服務(wù)端收到FIN發(fā)送ACK
3)服務(wù)端發(fā)送FIN
4)客戶(hù)端收到FIN發(fā)送ACK

假設(shè)有這種場(chǎng)景:假如第4步客戶(hù)端返回的ACK號(hào)丟失了臊泌,結(jié)果會(huì)如何呢鲤桥?這時(shí),服務(wù)器沒(méi)有接收到ACK號(hào)渠概,可能會(huì)重發(fā)一次FIN茶凳。如果這時(shí)客戶(hù)端的套接字已經(jīng)關(guān)閉刪除了,會(huì)發(fā)生什么事呢播揪?套接字被刪除贮喧,那么套接字中保存的控制信息也就跟著消失了,套接字對(duì)應(yīng)的端口號(hào)就會(huì)被釋放出來(lái)剪芍。這時(shí)塞淹,如果別的應(yīng)用程序要?jiǎng)?chuàng)建套接字,新套接字碰巧又被分配了同一個(gè)端口號(hào)罪裹,而服務(wù)器重發(fā)的FIN正好到達(dá)饱普,會(huì)怎么樣呢?本來(lái)這個(gè)FIN是要發(fā)給剛剛刪除的那個(gè)套接字的状共,但新套接字具有相同的端口號(hào)套耕,于是這個(gè)FIN就會(huì)錯(cuò)誤地跑到新套接字里面,新套接字就開(kāi)始執(zhí)行斷開(kāi)操作了峡继,這不亂了套了冯袍?

因?yàn)橹灰蛻?hù)端socket不刪除,就不會(huì)有新的socket綁定此端口碾牌,那應(yīng)該等待多久呢康愤?

這里就是上面所說(shuō)的2MSL了,根據(jù)MSL定義:一個(gè)TCP報(bào)文在Internet上的最長(zhǎng)生存時(shí)間舶吗,上面說(shuō)的情況頂多就是客戶(hù)端socket斷開(kāi)刪除之后征冷,第4步發(fā)送的ACK報(bào)文依然有效情況才會(huì)導(dǎo)致,那我們就一直等到這個(gè)報(bào)文失效了不就行了誓琼?那這樣看到貌似只要等待1MSL就夠了检激,那為啥還是2MSL呢肴捉?試想如果正好就在MSL臨界值,服務(wù)端以為收不到了重發(fā)了FIN報(bào)文叔收,那這種情況不是依然存在問(wèn)題嗎齿穗?所以保守起見(jiàn)再多等一下等到有可能重發(fā)的FIN報(bào)文也失效,這樣就不會(huì)有問(wèn)題啦饺律!

5.3 關(guān)于Wireshark

5.3.1 注意點(diǎn)一

tcp請(qǐng)求多了去了窃页,怎么才能準(zhǔn)確找到我想要的報(bào)文?

這里設(shè)置過(guò)濾就好了蓝晒,簡(jiǎn)單的方式就是根據(jù)端口過(guò)濾


image.png

5.3.2 注意點(diǎn)二

為什么過(guò)濾了之后腮出,什么也沒(méi)抓到?

這個(gè)要設(shè)置好抓包的網(wǎng)卡芝薇,因?yàn)槲覀兌际潜镜貑?dòng)的程序建立TCP胚嘲,所以這里要設(shè)置抓包lo0網(wǎng)卡


image.png

參考

TCP的11種狀態(tài)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市洛二,隨后出現(xiàn)的幾起案子馋劈,更是在濱河造成了極大的恐慌,老刑警劉巖晾嘶,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妓雾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡垒迂,警方通過(guò)查閱死者的電腦和手機(jī)械姻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)机断,“玉大人楷拳,你說(shuō)我怎么就攤上這事±艏椋” “怎么了欢揖?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奋蔚。 經(jīng)常有香客問(wèn)我她混,道長(zhǎng),這世上最難降的妖魔是什么泊碑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任坤按,我火速辦了婚禮,結(jié)果婚禮上馒过,老公的妹妹穿的比我還像新娘臭脓。我一直安慰自己,他們只是感情好沉桌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布谢鹊。 她就那樣靜靜地躺著,像睡著了一般留凭。 火紅的嫁衣襯著肌膚如雪佃扼。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天蔼夜,我揣著相機(jī)與錄音兼耀,去河邊找鬼。 笑死求冷,一個(gè)胖子當(dāng)著我的面吹牛瘤运,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匠题,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拯坟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了韭山?” 一聲冷哼從身側(cè)響起郁季,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钱磅,沒(méi)想到半個(gè)月后梦裂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盖淡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年年柠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片褪迟。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冗恨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牵咙,到底是詐尸還是另有隱情派近,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布洁桌,位于F島的核電站渴丸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏另凌。R本人自食惡果不足惜谱轨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吠谢。 院中可真熱鬧土童,春花似錦、人聲如沸工坊。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至罢吃,卻和暖如春楚午,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尿招。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工矾柜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人就谜。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓怪蔑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親丧荐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缆瓣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容