Linux上TCP丟失小包不可見的解決

2021-08-25 02:03:08 字數 1486 閱讀 6307

linux上tcp丟失小包不可見的解決

有網友在做乙個linux上的客戶端碰到這樣的問題:

我們在linux下開發乙個網路客戶端程式(伺服器是不可修改的),不斷向伺服器不定期傳送一些很小的包(一般只有幾十位元組),現在出現這種情況:大部分包正常傳送,但是當無線modem斷開的時候,如果這個時候剛好有乙個小包,就可能丟失,但在程式中卻顯示已經傳送成功,導致丟包。

我們分析原因是這樣:

1:主程式建立socket,tcp/ip方式,並採用stream方式

2:主程式呼叫write,寫入小包到系統的socket緩衝區,並返回成功寫入,由於位元組數很小,所以一般都立即返回寫入成功!

3:linux tcp/ip協議棧把socket緩衝區資料傳送到伺服器

如果第二步完成,剛好在第三步出現無線modem斷開的情況,就會導致主程式以為已經傳送成功了,但伺服器收不到的情況。

我們在網路上搜尋了大量的資料,但是沒有找到最終的解決方案,一般都是要求修改協議,加上對小包的ack處理,但我們這邊無法控**務器。

我們也試著控制keepalive和nodelay,但還是沒效果:

//對sock_cli設定keepalive和nodelay

len = sizeof(unsigned int);

setsockopt(sock_cli, sol_socket, so_keepalive, &optval, len);//使用keepalive

setsockopt(sock_cli, ipproto_tcp, tcp_nodelay, &optval, len);//禁用nagle演算法

請問有什麼方式可以解決這種情況?

如果是windows的,可以把核心的傳送buffer設為0,也就是socket的so_sndbuf選項。那麼直到伺服器tcp收到資料並ack了,客戶端的寫入才返回成功。

不過這種設so_sndbuf的方法在linux上是行不通的。linux不讓把傳送buffer設為0。

linux核心中的**是這樣的:

socket.c

可以看到,socket的傳送緩衝區sk_sndbuf是不讓你設的太大或太小的。你給的值太小(包括0),sk_sndbuf會被設為預設值sock_min_sndbuf,也就是2048.

以上多種方法(包括網友已經嘗試的多種方法),都在努力把資料即刻發出去,想在網路斷開時傳送完畢,結果都失敗。很多同型別方法都行不通的時候,可以試試換個思路。

該問題換一種說法是,當無線modem斷開時,有資料傳送沒成功,應用程式卻誤判為成功。

既然傳送失敗(有殘留沒傳送出去)已經不可避免,那麼就承認這個失敗。在這種情況下,客戶端要多做一步,找出這些殘留有多少。

使用linux的這個api

ioctl(tcp_socket, siocoutq, &value);

可以得到tcp socket傳送佇列裡頭還沒有傳送出去的資料有多少。

如果不為0,那麼證明最後一次傳送是沒有成功的,儘管寫入buffer成功。這時客戶端程式就顯示失敗就可以了。

secure crt連線不上linux服務端

場景描述 這裡敘述下我出現的問題,使用secure crt7.3連線linux服務端a 可以成功連線 連線服務端b卻不能成功連線,提示connection closed!選擇file trace options檢視詳細報錯資訊 問題分析 最開始我以為連線a能成功,b卻不能成功 就把問題放在了服務端b...

Linux遠端連線不上sqlyog

一.問題匯入 最近需要在linux部署專案,需要搭建環境。在linux下安裝好mysql後,重設了密碼。最後在使用sqlyog連線mysql過程中產生了一些問題。二.問題分析與解決 分析一 以為是密碼問題,重新輸入了好幾遍,但都不行。在網上看一些類似的解決的博文發現可能是以下兩個原因造成這種結果。1...

xshell連線不上linux問題

今天在自己的電腦上嘗試連線centos時,用xshell進行連線不上的問題,不管如何分配 各種各樣的方式全是了一遍後,發現最簡單的解決方法就是 在 中裝 配置時,直接就用橋接的模式。僅主機,橋接這三種模式,大白話介紹下 借用真實主機的 做自己的事情,類似於寄生蟲一樣,這樣說比較簡單 橋接 這個有意思...