0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

數(shù)據(jù)包的發(fā)送流程

xCb1_yikoulinux ? 來源:一口Linux ? 作者:一口Linux ? 2022-08-19 14:38 ? 次閱讀

表面上我是個(gè)技術(shù)博主。

但沒想到今天成了個(gè)情感博主。

我是沒想到有一天,我會(huì)通過技術(shù)知識(shí),來挽救粉絲即將破碎的感情。

掏心窩子的說。這件事情多少是沾點(diǎn)功德無量了。

事情是這樣的。

最近就有個(gè)讀者加了我的綠皮聊天軟件,女生,頭像挺好看的,就在我以為她要我拉她進(jìn)群發(fā)成人專升本廣告的時(shí)候。

畫風(fēng)突然不對(duì)勁。

她說她男朋友也是個(gè)程序員,異地戀,也關(guān)注了我,天天研究什么TCP,UDP網(wǎng)絡(luò)。一研究就是一晚上,一晚上都不回她消息的那種。

話里有話,懂。

不出意外的出了意外,她發(fā)出了靈魂拷問

"你們程序員真的有那么忙嗎?忙到連消息都不知道回。"

沒想到上來就是一記直拳。

但是,這一拳,我接住了。

我很想告訴她"分了吧,下一題"。

但我不能。因?yàn)檫@樣我就傷害了我的讀者兄弟。

沉默了一下。

單核cpu都快轉(zhuǎn)冒煙了,才顫顫巍巍在九宮格鍵盤上發(fā)出消息。

再回慢一點(diǎn),我就感覺,我要對(duì)不起我這全日制本科學(xué)歷了。

"其實(shí),他已經(jīng)回了你消息了,但你知道嗎?網(wǎng)絡(luò)是會(huì)丟包的。"

"我來幫他解釋下,這個(gè)話題就要從數(shù)據(jù)包的發(fā)送流程聊起"

數(shù)據(jù)包的發(fā)送流程

首先,我們兩個(gè)手機(jī)的綠皮聊天軟件客戶端,要通信,中間會(huì)通過它們家服務(wù)器。大概長(zhǎng)這樣。

a5b1bf50-1f85-11ed-ba43-dac502259ad0.png聊天軟件三端通信

但為了簡(jiǎn)化模型,我們把中間的服務(wù)器給省略掉,假設(shè)這是個(gè)端到端的通信。且為了保證消息的可靠性,我們盲猜它們之間用的是TCP協(xié)議進(jìn)行通信。

a5c106fe-1f85-11ed-ba43-dac502259ad0.png聊天軟件兩端通信

為了發(fā)送數(shù)據(jù)包,兩端首先會(huì)通過三次握手,建立TCP連接。

一個(gè)數(shù)據(jù)包,從聊天框里發(fā)出,消息會(huì)從聊天軟件所在的用戶空間拷貝到內(nèi)核空間發(fā)送緩沖區(qū)(send buffer),數(shù)據(jù)包就這樣順著傳輸層、網(wǎng)絡(luò)層,進(jìn)入到數(shù)據(jù)鏈路層,在這里數(shù)據(jù)包會(huì)經(jīng)過流控(qdisc),再通過RingBuffer發(fā)到物理層的網(wǎng)卡。數(shù)據(jù)就這樣順著網(wǎng)卡發(fā)到了紛繁復(fù)雜的網(wǎng)絡(luò)世界里。這里頭數(shù)據(jù)會(huì)經(jīng)過n多個(gè)路由器和交換機(jī)之間的跳轉(zhuǎn),最后到達(dá)目的機(jī)器的網(wǎng)卡處。

此時(shí)目的機(jī)器的網(wǎng)卡會(huì)通知DMA將數(shù)據(jù)包信息放到RingBuffer中,再觸發(fā)一個(gè)硬中斷CPUCPU觸發(fā)軟中斷ksoftirqdRingBuffer收包,于是一個(gè)數(shù)據(jù)包就這樣順著物理層,數(shù)據(jù)鏈路層,網(wǎng)絡(luò)層,傳輸層,最后從內(nèi)核空間拷貝到用戶空間里的聊天軟件里。

a5d4e052-1f85-11ed-ba43-dac502259ad0.png網(wǎng)絡(luò)發(fā)包收包全景圖

畫了那么大一張圖,只水了200字做解釋,我多少是有些心痛的。

到這里,拋開一些細(xì)節(jié),大家大概知道了一個(gè)數(shù)據(jù)包從發(fā)送到接收的宏觀過程。

可以看到,這上面全是密密麻麻的名詞

整條鏈路下來,有不少地方可能會(huì)發(fā)生丟包。

但為了不讓大家保持蹲姿太久影響身體健康,我這邊只重點(diǎn)講下幾個(gè)常見容易發(fā)生丟包的場(chǎng)景

建立連接時(shí)丟包

TCP協(xié)議會(huì)通過三次握手建立連接。大概長(zhǎng)下面這樣。

a5e81c80-1f85-11ed-ba43-dac502259ad0.pngTCP三次握手

在服務(wù)端,第一次握手之后,會(huì)先建立個(gè)半連接,然后再發(fā)出第二次握手。這時(shí)候需要有個(gè)地方可以暫存這些半連接。這個(gè)地方就叫半連接隊(duì)列

如果之后第三次握手來了,半連接就會(huì)升級(jí)為全連接,然后暫存到另外一個(gè)叫全連接隊(duì)列的地方,坐等程序執(zhí)行accept()方法將其取走使用。

a5f8a884-1f85-11ed-ba43-dac502259ad0.png半連接隊(duì)列和全連接隊(duì)列

是隊(duì)列就有長(zhǎng)度,有長(zhǎng)度就有可能會(huì)滿,如果它們滿了,那新來的包就會(huì)被丟棄。

可以通過下面的方式查看是否存在這種丟包行為。

#全連接隊(duì)列溢出次數(shù)
#netstat-s|grepoverflowed
4343timesthelistenqueueofasocketoverflowed

#半連接隊(duì)列溢出次數(shù)
#netstat-s|grep-i"SYNstoLISTENsocketsdropped"
109timesthelistenqueueofasocketoverflowed

從現(xiàn)象來看就是連接建立失敗。

a607ab90-1f85-11ed-ba43-dac502259ad0.png

這個(gè)話題在之前寫的《沒有accept,能建立TCP連接嗎?》有更詳細(xì)的聊過,感興趣的可以回去看下。

流量控制丟包

應(yīng)用層能發(fā)網(wǎng)絡(luò)數(shù)據(jù)包的軟件有那么多,如果所有數(shù)據(jù)不加控制一股腦沖入到網(wǎng)卡,網(wǎng)卡會(huì)吃不消,那怎么辦?讓數(shù)據(jù)按一定的規(guī)則排個(gè)隊(duì)依次處理,也就是所謂的qdisc(Queueing Disciplines,排隊(duì)規(guī)則),這也是我們常說的流量控制機(jī)制。

排隊(duì),得先有個(gè)隊(duì)列,而隊(duì)列有個(gè)長(zhǎng)度。

我們可以通過下面的ifconfig命令查看到,里面涉及到的txqueuelen后面的數(shù)字1000,其實(shí)就是流控隊(duì)列的長(zhǎng)度。

當(dāng)發(fā)送數(shù)據(jù)過快,流控隊(duì)列長(zhǎng)度txqueuelen又不夠大時(shí),就容易出現(xiàn)丟包現(xiàn)象。

a619eef4-1f85-11ed-ba43-dac502259ad0.pngqdisc丟包

可以通過下面的ifconfig命令,查看TX下的dropped字段,當(dāng)它大于0時(shí),則有可能是發(fā)生了流控丟包。

#ifconfigeth0
eth0:flags=4163mtu1500
inet172.21.66.69netmask255.255.240.0broadcast172.21.79.255
inet6fe80:3eff269fprefixlen64scopeid0x20
ether003e26:9ftxqueuelen1000(Ethernet)
RXpackets6962682bytes1119047079(1.0GiB)
RXerrors0dropped0overruns0frame0
TXpackets9688919bytes2072511384(1.9GiB)
TXerrors0dropped0overruns0carrier0collisions0

當(dāng)遇到這種情況時(shí),我們可以嘗試修改下流控隊(duì)列的長(zhǎng)度。比如像下面這樣將eth0網(wǎng)卡的流控隊(duì)列長(zhǎng)度從1000提升為1500.

#ifconfigeth0txqueuelen1500

網(wǎng)卡丟包

網(wǎng)卡和它的驅(qū)動(dòng)導(dǎo)致丟包的場(chǎng)景也比較常見,原因很多,比如網(wǎng)線質(zhì)量差,接觸不良。除此之外,我們來聊幾個(gè)常見的場(chǎng)景。

RingBuffer過小導(dǎo)致丟包

上面提到,在接收數(shù)據(jù)時(shí),會(huì)將數(shù)據(jù)暫存到RingBuffer接收緩沖區(qū)中,然后等著內(nèi)核觸發(fā)軟中斷慢慢收走。如果這個(gè)緩沖區(qū)過小,而這時(shí)候發(fā)送的數(shù)據(jù)又過快,就有可能發(fā)生溢出,此時(shí)也會(huì)產(chǎn)生丟包。

a625532a-1f85-11ed-ba43-dac502259ad0.pngRingBuffer滿了導(dǎo)致丟包

我們可以通過下面的命令去查看是否發(fā)生過這樣的事情。

#ifconfig
eth0:RXerrors0dropped0overruns0frame0

查看上面的overruns指標(biāo),它記錄了由于RingBuffer長(zhǎng)度不足導(dǎo)致的溢出次數(shù)。

當(dāng)然,用ethtool命令也能查看。

#ethtool-Seth0|greprx_queue_0_drops

但這里需要注意的是,因?yàn)橐粋€(gè)網(wǎng)卡里是可以有多個(gè)RingBuffer的,所以上面的rx_queue_0_drops里的0代表的是第0個(gè)RingBuffer的丟包數(shù),對(duì)于多隊(duì)列的網(wǎng)卡,這個(gè)0還可以改成其他數(shù)字。但我的家庭條件不允許我看其他隊(duì)列的丟包數(shù),所以上面的命令對(duì)我來說是夠用了。。。

當(dāng)發(fā)現(xiàn)有這類型丟包的時(shí)候,可以通過下面的命令查看當(dāng)前網(wǎng)卡的配置。

#ethtool-geth0
Ringparametersforeth0:
Pre-setmaximums:
RX:4096
RXMini:0
RXJumbo:0
TX:4096
Currenthardwaresettings:
RX:1024
RXMini:0
RXJumbo:0
TX:1024

上面的輸出內(nèi)容,含義是RingBuffer最大支持4096的長(zhǎng)度,但現(xiàn)在實(shí)際只用了1024。

想要修改這個(gè)長(zhǎng)度可以執(zhí)行ethtool -G eth1 rx 4096 tx 4096將發(fā)送和接收RingBuffer的長(zhǎng)度都改為4096。

RingBuffer增大之后,可以減少因?yàn)槿萘啃《鴮?dǎo)致的丟包情況。

網(wǎng)卡性能不足

網(wǎng)卡作為硬件,傳輸速度是有上限的。當(dāng)網(wǎng)絡(luò)傳輸速度過大,達(dá)到網(wǎng)卡上限時(shí),就會(huì)發(fā)生丟包。這種情況一般常見于壓測(cè)場(chǎng)景。

我們可以通過ethtool加網(wǎng)卡名,獲得當(dāng)前網(wǎng)卡支持的最大速度。

#ethtooleth0
Settingsforeth0:
Speed:10000Mb/s

可以看到,我這邊用的網(wǎng)卡能支持的最大傳輸速度speed=1000Mb/s

也就是俗稱的千兆網(wǎng)卡,但注意這里的單位是Mb,這里的b是指bit,而不是Byte。1Byte=8bit。所以10000Mb/s還要除以8,也就是理論上網(wǎng)卡最大傳輸速度是1000/8 = 125MB/s。

我們可以通過sar命令從網(wǎng)絡(luò)接口層面來分析數(shù)據(jù)包的收發(fā)情況。

#sar-nDEV1
Linux3.10.0-1127.19.1.el7.x86_642022年07月27日_x86_64_(1CPU)

08時(shí)35分39秒IFACErxpck/stxpck/srxkB/stxkB/srxcmp/stxcmp/srxmcst/s
08時(shí)35分40秒eth06.064.040.35121682.330.000.000.00

其中 txkB/s是指當(dāng)前每秒發(fā)送的字節(jié)(byte)總數(shù),rxkB/s是指每秒接收的字節(jié)(byte)總數(shù)。

當(dāng)兩者加起來的值約等于12~13w字節(jié)的時(shí)候,也就對(duì)應(yīng)大概125MB/s的傳輸速度。此時(shí)達(dá)到網(wǎng)卡性能極限,就會(huì)開始丟包。

遇到這個(gè)問題,優(yōu)先看下你的服務(wù)是不是真有這么大的真實(shí)流量,如果是的話可以考慮下拆分服務(wù),或者就忍痛充錢升級(jí)下配置吧。

接收緩沖區(qū)丟包

我們一般使用TCP socket進(jìn)行網(wǎng)絡(luò)編程的時(shí)候,內(nèi)核都會(huì)分配一個(gè)發(fā)送緩沖區(qū)和一個(gè)接收緩沖區(qū)。

當(dāng)我們想要發(fā)一個(gè)數(shù)據(jù)包,會(huì)在代碼里執(zhí)行send(msg),這時(shí)候數(shù)據(jù)包并不是一把梭直接就走網(wǎng)卡飛出去的。而是將數(shù)據(jù)拷貝到內(nèi)核發(fā)送緩沖區(qū)就完事返回了,至于什么時(shí)候發(fā)數(shù)據(jù),發(fā)多少數(shù)據(jù),這個(gè)后續(xù)由內(nèi)核自己做決定。之前寫過的《代碼執(zhí)行send成功后,數(shù)據(jù)就發(fā)出去了嗎?》里有比較詳細(xì)的介紹。

a6324526-1f85-11ed-ba43-dac502259ad0.pngtcp_sendmsg邏輯

接收緩沖區(qū)作用也類似,從外部網(wǎng)絡(luò)收到的數(shù)據(jù)包就暫存在這個(gè)地方,然后坐等用戶空間的應(yīng)用程序?qū)?shù)據(jù)包取走。

這兩個(gè)緩沖區(qū)是有大小限制的,可以通過下面的命令去查看。

#查看接收緩沖區(qū)
#sysctlnet.ipv4.tcp_rmem
net.ipv4.tcp_rmem=4096873806291456

#查看發(fā)送緩沖區(qū)
#sysctlnet.ipv4.tcp_wmem
net.ipv4.tcp_wmem=4096163844194304

不管是接收緩沖區(qū)還是發(fā)送緩沖區(qū),都能看到三個(gè)數(shù)值,分別對(duì)應(yīng)緩沖區(qū)的最小值,默認(rèn)值和最大值 (min、default、max)。緩沖區(qū)會(huì)在min和max之間動(dòng)態(tài)調(diào)整。

那么問題來了,如果緩沖區(qū)設(shè)置過小會(huì)怎么樣?

對(duì)于發(fā)送緩沖區(qū),執(zhí)行send的時(shí)候,如果是阻塞調(diào)用,那就會(huì)等,等到緩沖區(qū)有空位可以發(fā)數(shù)據(jù)。

a64252c2-1f85-11ed-ba43-dac502259ad0.gif

send阻塞

如果是非阻塞調(diào)用,就會(huì)立刻返回一個(gè) EAGAIN 錯(cuò)誤信息,意思是 Try again 。讓應(yīng)用程序下次再重試。這種情況下一般不會(huì)發(fā)生丟包。

a65f6646-1f85-11ed-ba43-dac502259ad0.gif

send非阻塞

當(dāng)接受緩沖區(qū)滿了,事情就不一樣了,它的TCP接收窗口會(huì)變?yōu)?,也就是所謂的零窗口,并且會(huì)通過數(shù)據(jù)包里的win=0,告訴發(fā)送端,"球球了,頂不住了,別發(fā)了"。一般這種情況下,發(fā)送端就該停止發(fā)消息了,但如果這時(shí)候確實(shí)還有數(shù)據(jù)發(fā)來,就會(huì)發(fā)生丟包。

a66d7e48-1f85-11ed-ba43-dac502259ad0.pngrecv_buffer丟包

我們可以通過下面的命令里的TCPRcvQDrop查看到有沒有發(fā)生過這種丟包現(xiàn)象。

cat/proc/net/netstat
TcpExt:SyncookiesSentTCPRcvQDropSyncookiesFailed
TcpExt:015760116

但是說個(gè)傷心的事情,我們一般也看不到這個(gè)TCPRcvQDrop,因?yàn)檫@個(gè)是5.9版本里引入的打點(diǎn),而我們的服務(wù)器用的一般是2.x~3.x左右版本。你可以通過下面的命令查看下你用的是什么版本的linux內(nèi)核。

#cat/proc/version
Linuxversion3.10.0-1127.19.1.el7.x86_64

兩端之間的網(wǎng)絡(luò)丟包

前面提到的是兩端機(jī)器內(nèi)部的網(wǎng)絡(luò)丟包,除此之外,兩端之間那么長(zhǎng)的一條鏈路都屬于外部網(wǎng)絡(luò),這中間有各種路由器和交換機(jī)還有光纜啥的,丟包也是很經(jīng)常發(fā)生的。

這些丟包行為發(fā)生在中間鏈路的某些個(gè)機(jī)器上,我們當(dāng)然是沒權(quán)限去登錄這些機(jī)器。但我們可以通過一些命令觀察整個(gè)鏈路的連通情況。

ping命令查看丟包

比如我們知道目的地的域名是 baidu.com。想知道你的機(jī)器到baidu服務(wù)器之間,有沒有產(chǎn)生丟包行為??梢允褂胮ing命令。

a67caa3a-1f85-11ed-ba43-dac502259ad0.pngping查看丟包

倒數(shù)第二行里有個(gè)100% packet loss,意思是丟包率100%。

但這樣其實(shí)你只能知道你的機(jī)器和目的機(jī)器之間有沒有丟包。

那如果你想知道你和目的機(jī)器之間的這條鏈路,哪個(gè)節(jié)點(diǎn)丟包了,有沒有辦法呢?

有。

mtr命令

mtr命令可以查看到你的機(jī)器和目的機(jī)器之間的每個(gè)節(jié)點(diǎn)的丟包情況。

像下面這樣執(zhí)行命令。

a6885f60-1f85-11ed-ba43-dac502259ad0.pngmtr_icmp

其中-r是指report,以報(bào)告的形式打印結(jié)果。

可以看到Host那一列,出現(xiàn)的都是鏈路中間每一跳的機(jī)器,Loss的那一列就是指這一跳對(duì)應(yīng)的丟包率。

需要注意的是,中間有一些是host是???,那個(gè)是因?yàn)?strong style="font-size:inherit;line-height:inherit;margin:0px;padding:0px;font-weight:bold;color:rgb(41,98,255);">mtr默認(rèn)用的是ICMP包,有些節(jié)點(diǎn)限制了ICMP包,導(dǎo)致不能正常展示。

我們可以在mtr命令里加個(gè)-u,也就是使用udp包,就能看到部分???對(duì)應(yīng)的IP。

a6a263c4-1f85-11ed-ba43-dac502259ad0.pngmtr-udp

ICMP包和UDP包的結(jié)果拼在一起看,就是比較完整的鏈路圖了。

還有個(gè)小細(xì)節(jié),Loss那一列,我們?cè)趇cmp的場(chǎng)景下,關(guān)注最后一行,如果是0%,那不管前面loss是100%還是80%都無所謂,那些都是節(jié)點(diǎn)限制導(dǎo)致的虛報(bào)。

但如果最后一行是20%,再往前幾行都是20%左右,那說明丟包就是從最接近的那一行開始產(chǎn)生的,長(zhǎng)時(shí)間是這樣,那很可能這一跳出了點(diǎn)問題。如果是公司內(nèi)網(wǎng)的話,你可以帶著這條線索去找對(duì)應(yīng)的網(wǎng)絡(luò)同事。如果是外網(wǎng)的話,那耐心點(diǎn)等等吧,別人家的開發(fā)會(huì)比你更著急。

a6ada52c-1f85-11ed-ba43-dac502259ad0.png

發(fā)生丟包了怎么辦

說了這么多。只是想告訴大家,丟包是很常見的,幾乎不可避免的一件事情。

但問題來了,發(fā)生丟包了怎么辦?

這個(gè)好辦,用TCP協(xié)議去做傳輸。

a6caf708-1f85-11ed-ba43-dac502259ad0.pngTCP是什么

建立了TCP連接的兩端,發(fā)送端在發(fā)出數(shù)據(jù)后會(huì)等待接收端回復(fù)ack包ack包的目的是為了告訴對(duì)方自己確實(shí)收到了數(shù)據(jù),但如果中間鏈路發(fā)生了丟包,那發(fā)送端會(huì)遲遲收不到確認(rèn)ack,于是就會(huì)進(jìn)行重傳。以此來保證每個(gè)數(shù)據(jù)包都確確實(shí)實(shí)到達(dá)了接收端。

假設(shè)現(xiàn)在網(wǎng)斷了,我們還用聊天軟件發(fā)消息,聊天軟件會(huì)使用TCP不斷嘗試重傳數(shù)據(jù),如果重傳期間網(wǎng)絡(luò)恢復(fù)了,那數(shù)據(jù)就能正常發(fā)過去。但如果多次重試直到超時(shí)都還是失敗,這時(shí)候你將收獲一個(gè)紅色感嘆號(hào)。

這時(shí)候問題又來了。

假設(shè)某綠皮聊天軟件用的就是TCP協(xié)議。

那文章開頭提到的女生,她男朋友回她的消息時(shí)為什么還會(huì)丟包?畢竟丟包了會(huì)重試,重試失敗了還會(huì)出現(xiàn)紅色感嘆號(hào)。

于是乎,問題就變成了,用了TCP協(xié)議,就一定不會(huì)丟包嗎?

用了TCP協(xié)議就一定不會(huì)丟包嗎

我們知道TCP位于傳輸層,在它的上面還有各種應(yīng)用層協(xié)議,比如常見的HTTP或者各類RPC協(xié)議。

a6e6567e-1f85-11ed-ba43-dac502259ad0.png四層網(wǎng)絡(luò)協(xié)議

TCP保證的可靠性,是傳輸層的可靠性。也就是說,TCP只保證數(shù)據(jù)從A機(jī)器的傳輸層可靠地發(fā)到B機(jī)器的傳輸層。

至于數(shù)據(jù)到了接收端的傳輸層之后,能不能保證到應(yīng)用層,TCP并不管。

假設(shè)現(xiàn)在,我們輸入一條消息,從聊天框發(fā)出,走到傳輸層TCP協(xié)議的發(fā)送緩沖區(qū),不管中間有沒有丟包,最后通過重傳都保證發(fā)到了對(duì)方的傳輸層TCP接收緩沖區(qū),此時(shí)接收端回復(fù)了一個(gè)ack,發(fā)送端收到這個(gè)ack后就會(huì)將自己發(fā)送緩沖區(qū)里的消息給扔掉。到這里TCP的任務(wù)就結(jié)束了。

TCP任務(wù)是結(jié)束了,但聊天軟件的任務(wù)沒結(jié)束。

聊天軟件還需要將數(shù)據(jù)從TCP的接收緩沖區(qū)里讀出來,如果在讀出來這一刻,手機(jī)由于內(nèi)存不足或其他各種原因,導(dǎo)致軟件崩潰閃退了。

發(fā)送端以為自己發(fā)的消息已經(jīng)發(fā)給對(duì)方了,但接收端卻并沒有收到這條消息。

于是乎,消息就丟了。

a6f13ab2-1f85-11ed-ba43-dac502259ad0.png使用TCP協(xié)議卻發(fā)生丟包

雖然概率很小,但它就是發(fā)生了。

合情合理,邏輯自洽。

所以從這里,我鏗鏘有力的得出結(jié)論,我的讀者已經(jīng)回了這位女生消息了,只是因?yàn)榘l(fā)生了丟包所以女生才沒能收到,而丟包的原因是女生的手機(jī)聊天軟件在接收消息的那一刻發(fā)生了閃退。

到這里。女生知道自己錯(cuò)怪她男朋友了,哭著表示,一定要讓她男朋友給她買一臺(tái)不閃退的最新iphone

額。。。

兄弟們覺得我做得對(duì)的,請(qǐng)?jiān)谠u(píng)論區(qū)扣個(gè)"正能量"。

這類丟包問題怎么解決?

故事到這里也到尾聲了,感動(dòng)之余,我們來聊點(diǎn)掏心窩子的話。

其實(shí)前面說的都對(duì),沒有一句是假話

但某綠皮聊天軟件這么成熟,怎么可能沒考慮過這一點(diǎn)呢。

大家應(yīng)該還記得我們文章開頭提到過,為了簡(jiǎn)單,就將服務(wù)器那一方給省略了,從三端通信變成了兩端通信,所以才有了這個(gè)丟包問題。

現(xiàn)在我們重新將服務(wù)器加回來。

a5b1bf50-1f85-11ed-ba43-dac502259ad0.png聊天軟件三端通信

大家有沒有發(fā)現(xiàn),有時(shí)候我們?cè)谑謾C(jī)里聊了一大堆內(nèi)容,然后登錄電腦版,它能將最近的聊天記錄都同步到電腦版上。也就是說服務(wù)器可能記錄了我們最近發(fā)過什么數(shù)據(jù),假設(shè)每條消息都有個(gè)id,服務(wù)器和聊天軟件每次都拿最新消息的id進(jìn)行對(duì)比,就能知道兩端消息是否一致,就像對(duì)賬一樣。

對(duì)于發(fā)送方,只要定時(shí)跟服務(wù)端的內(nèi)容對(duì)賬一下,就知道哪條消息沒發(fā)送成功,直接重發(fā)就好了。

如果接收方的聊天軟件崩潰了,重啟后跟服務(wù)器稍微通信一下就知道少了哪條數(shù)據(jù),同步上來就是了,所以也不存在上面提到的丟包情況。

可以看出,TCP只保證傳輸層的消息可靠性,并不保證應(yīng)用層的消息可靠性。如果我們還想保證應(yīng)用層的消息可靠性,就需要應(yīng)用層自己去實(shí)現(xiàn)邏輯做保證。

那么問題叒來了,兩端通信的時(shí)候也能對(duì)賬,為什么還要引入第三端服務(wù)器?

主要有三個(gè)原因。

  • 第一,如果是兩端通信,你聊天軟件里有1000個(gè)好友,你就得建立1000個(gè)連接。但如果引入服務(wù)端,你只需要跟服務(wù)器建立1個(gè)連接就夠了,聊天軟件消耗的資源越少,手機(jī)就越省電。

  • 第二,就是安全問題,如果還是兩端通信,隨便一個(gè)人找你對(duì)賬一下,你就把聊天記錄給同步過去了,這并不合適吧。如果對(duì)方別有用心,信息就泄露了。引入第三方服務(wù)端就可以很方便的做各種鑒權(quán)校驗(yàn)。

  • 第三,是軟件版本問題。軟件裝到用戶手機(jī)之后,軟件更不更新就是由用戶說了算了。如果還是兩端通信,且兩端的軟件版本跨度太大,很容易產(chǎn)生各種兼容性問題,但引入第三端服務(wù)器,就可以強(qiáng)制部分過低版本升級(jí),否則不能使用軟件。但對(duì)于大部分兼容性問題,給服務(wù)端加兼容邏輯就好了,不需要強(qiáng)制用戶更新軟件。

所以看到這里大家應(yīng)該明白了,我把服務(wù)端去掉,并不單純是為了簡(jiǎn)單。

總結(jié)

  • 數(shù)據(jù)從發(fā)送端到接收端,鏈路很長(zhǎng),任何一個(gè)地方都可能發(fā)生丟包,幾乎可以說丟包不可避免。

  • 平時(shí)沒事也不用關(guān)注丟包,大部分時(shí)候TCP的重傳機(jī)制保證了消息可靠性。

  • 當(dāng)你發(fā)現(xiàn)服務(wù)異常的時(shí)候,比如接口延時(shí)很高,總是失敗的時(shí)候,可以用ping或者mtr命令看下是不是中間鏈路發(fā)生了丟包。

  • TCP只保證傳輸層的消息可靠性,并不保證應(yīng)用層的消息可靠性。如果我們還想保證應(yīng)用層的消息可靠性,就需要應(yīng)用層自己去實(shí)現(xiàn)邏輯做保證。

最后給大家留個(gè)問題吧,mtr命令是怎么知道每一跳的IP地址的


審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 通信
    +關(guān)注

    關(guān)注

    18

    文章

    6032

    瀏覽量

    135995
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1353

    瀏覽量

    79077
  • 數(shù)據(jù)包
    +關(guān)注

    關(guān)注

    0

    文章

    261

    瀏覽量

    24396

原文標(biāo)題:用了TCP協(xié)議,就一定不會(huì)丟包嗎?

文章出處:【微信號(hào):yikoulinux,微信公眾號(hào):一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    mtu配置步驟詳解 mtu與數(shù)據(jù)包丟失的關(guān)系

    MTU(Maximum Transmission Unit)即最大傳輸單元,是指一種通信協(xié)議的某一層上面所能通過的最大數(shù)據(jù)報(bào)大小,單位是字節(jié)。MTU配置步驟及其與數(shù)據(jù)包丟失的關(guān)系如下: MTU配置
    的頭像 發(fā)表于 12-16 14:33 ?530次閱讀

    低功耗Bluetooth–有關(guān)CC1350和CC26x0器件通過SPI發(fā)送的UNPI數(shù)據(jù)包缺失長(zhǎng)度檢查

    電子發(fā)燒友網(wǎng)站提供《低功耗Bluetooth–有關(guān)CC1350和CC26x0器件通過SPI發(fā)送的UNPI數(shù)據(jù)包缺失長(zhǎng)度檢查.pdf》資料免費(fèi)下載
    發(fā)表于 09-20 10:49 ?0次下載
    低功耗Bluetooth–有關(guān)CC1350和CC26x0器件通過SPI<b class='flag-5'>發(fā)送</b>的UNPI<b class='flag-5'>數(shù)據(jù)包</b>缺失長(zhǎng)度檢查

    esp8266怎么做才能每秒發(fā)送更多的數(shù)據(jù)包呢?

    數(shù)據(jù)包的速度,即每秒大約 50 個(gè) UDP 數(shù)據(jù)包。高波特率唯一改變的是,在數(shù)據(jù)包較大的情況下,我可以以與輕量級(jí)數(shù)據(jù)包相同的速度發(fā)送
    發(fā)表于 07-22 08:00

    使用AT SAVETRANSLINK時(shí)UDP數(shù)據(jù)包丟失怎么解決?

    Android 發(fā)送一個(gè)小 UDP 數(shù)據(jù)包(5 字節(jié))。這個(gè)小數(shù)據(jù)包被我的微控制器在UART上接收到。微控制器將更大的數(shù)據(jù)包(可變長(zhǎng)度,約 100 字節(jié))
    發(fā)表于 07-18 07:17

    能否在ESP結(jié)束之前通過串行端口停止傳入的UDP數(shù)據(jù)包的傳輸以解析下一個(gè)UDP數(shù)據(jù)包?

    丟棄在ESP完成之前不需要的數(shù)據(jù)包,以便通過串行端口發(fā)送它以接收下一個(gè)數(shù)據(jù)包, 如果沒有,我必須按順序讀取所有傳入的數(shù)據(jù)包,需要的和不需要的, 而且波特率不足,主機(jī)處理器開銷大, 我
    發(fā)表于 07-16 06:18

    將UDP數(shù)據(jù)包發(fā)送到廣播IP地址時(shí)遇到的疑問求解

    當(dāng) wroom 充當(dāng)主機(jī),我們嘗試將 UDP 數(shù)據(jù)包發(fā)送到與 wroom 位于同一網(wǎng)段的廣播 IP 地址時(shí),(wroom IP 10.11.12.1,發(fā)送到 IP 10.11.12.255),我們
    發(fā)表于 07-16 06:07

    如何直接從phy mac層發(fā)送和接收802.11數(shù)據(jù)包

    我閱讀了完整的文檔(espressif_iot_esp8266ex_development_kit_v0.9.4.zip),但我沒有找到答案: 是否可以訪問 802.11 數(shù)據(jù)包,并通過應(yīng)用程序處理它們? 我希望能夠直接從 phy mac 層發(fā)送和接收 802.11
    發(fā)表于 07-15 08:03

    請(qǐng)問如何使用AT CIPSEND或AT CIPSENDBUF發(fā)送多個(gè)數(shù)據(jù)包?

    我可以使用 AT CIPSEND 發(fā)送單個(gè)數(shù)據(jù)包。但是我必須發(fā)送一系列二進(jìn)制數(shù)據(jù)包。如何使用AT CISEND或AT CIPSENDBUF發(fā)送
    發(fā)表于 07-15 07:37

    NONOS如何檢查是否實(shí)際發(fā)送了UDP數(shù)據(jù)包?

    我發(fā)現(xiàn)進(jìn)入深度睡眠通常無法傳輸發(fā)送的最后一個(gè) UDP 數(shù)據(jù)包。我現(xiàn)在將睡眠延遲 30 毫秒,這是一個(gè)黑客。 我寧愿有一種方法來檢查是否可以休眠,或者以其他方式能夠注冊(cè)指示數(shù)據(jù)包發(fā)送
    發(fā)表于 07-12 06:14

    加入IGMP組后,數(shù)據(jù)包不再通過UDP發(fā)送,為什么?

    有誰知道IGMP_Join后發(fā)送數(shù)據(jù)包需要什么 似乎在加入IGMP組后,數(shù)據(jù)包不再通過UDP發(fā)送。 在下面的示例中,第一個(gè)數(shù)據(jù)包總是被
    發(fā)表于 07-10 07:20

    在AN65974中短數(shù)據(jù)包和零長(zhǎng)數(shù)據(jù)包是什么意思?

    在 AN65974 中,短數(shù)據(jù)包和零長(zhǎng)數(shù)據(jù)包是什么意思? 非常感謝!
    發(fā)表于 05-30 07:41

    如何在AIROC GUI上獲取良好數(shù)據(jù)包和總數(shù)據(jù)包?

    使用 IQxel-MW LifePoint 作為發(fā)生器并發(fā)送波形BT_1DH5_00001111_Fs80M.iqvsg,但無法在 AIROC 工具中接收數(shù)據(jù)包。 以下是從 IQxel 發(fā)送
    發(fā)表于 05-22 06:39

    請(qǐng)問高端網(wǎng)絡(luò)芯片如何處理數(shù)據(jù)包呢?

    隨著網(wǎng)絡(luò)芯片帶寬的持續(xù)提升,其內(nèi)部數(shù)據(jù)包處理單元的工作負(fù)載也隨之增加。然而,如果處理單元無法與網(wǎng)絡(luò)接口的傳入速率相匹配,將無法及時(shí)處理數(shù)據(jù)包,這不僅會(huì)導(dǎo)致數(shù)據(jù)包隨機(jī)丟失,更會(huì)降低網(wǎng)絡(luò)的吞吐量。
    的頭像 發(fā)表于 04-02 16:36 ?632次閱讀
    請(qǐng)問高端網(wǎng)絡(luò)芯片如何處理<b class='flag-5'>數(shù)據(jù)包</b>呢?

    STM32H7接收數(shù)據(jù)包異常,一接收的數(shù)據(jù)出現(xiàn)兩發(fā)送的內(nèi)容怎么解決?

    );__HAL_UART_DISABLE_IT( huart1, DMA_IT_HT); 2、發(fā)送數(shù)據(jù)包1
    發(fā)表于 03-08 08:05

    DPDK在AI驅(qū)動(dòng)的高效數(shù)據(jù)包處理應(yīng)用

    傳統(tǒng)的數(shù)據(jù)包處理方式是數(shù)據(jù)包先到內(nèi)核最后再到用戶層進(jìn)行處理。這種方式會(huì)增加額外的延遲和CPU開銷,嚴(yán)重影響數(shù)據(jù)包處理的性能。 DPDK 繞過內(nèi)核,在用戶空間中實(shí)現(xiàn)快速數(shù)據(jù)包處理。
    的頭像 發(fā)表于 02-25 11:28 ?944次閱讀
    DPDK在AI驅(qū)動(dòng)的高效<b class='flag-5'>數(shù)據(jù)包</b>處理應(yīng)用