日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀] 環(huán)境:Client 通過tcp 連接server,server端只是listen,但是不調(diào)用accept。通過netstat –ant查看兩端的連接情況。server端listen,不調(diào)用accept。client一直去con

 環(huán)境:

Client 通過tcp 連接server,server端只是listen,但是不調(diào)用accept。通過netstat –ant查看兩端的連接情況。

server端listen,不調(diào)用accept。

client一直去connect server。

問題:

運行一段時間后,為什么server端的ESTABLISHED連接的個數(shù)基本是固定的129個,但是client端的ESTABLISHED連接的個數(shù)卻在不斷增加?

分析

Linux內(nèi)核協(xié)議棧為一個tcp連接管理使用兩個隊列,一個是半鏈接隊列(用來保存處于SYN_SENT和SYN_RECV狀態(tài)的請求),一個是accpetd隊列(用來保存處于established狀態(tài),但是應(yīng)用層沒有調(diào)用accept取走的請求)。

第一個隊列的長度是/proc/sys/net/ipv4/tcp_max_syn_backlog,默認是1024。如果開啟了syncookies,那么基本上沒有限制。

第二個隊列的長度是/proc/sys/net/core/somaxconn,默認是128,表示最多有129個established鏈接等待accept。(為什么是129?詳見下面的附錄1)。

現(xiàn)在假設(shè)acceptd隊列已經(jīng)達到129的情況:

client發(fā)送syn到server。client(SYN_SENT),server(SYN_RECV)

server端處理流程:tcp_v4_do_rcv--->tcp_rcv_state_process--->tcp_v4_conn_request

if(sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_yong(sk)>1)

goto drop;

inet_csk_reqsk_queue_yong(sk)的含義是請求隊列中有多少個握手過程中沒有重傳過的段。

在第一次的時候,之前的握手過程都沒有重傳過,所以這個syn包server端會直接drop掉,之后client會重傳syn,當inet_csk_reqsk_queue_yong(sk) < 1,那么這個syn被server端接受。server會回復(fù)synack給client。這樣一來兩邊的狀態(tài)就變?yōu)閏lient(ESTABLISHED), server(SYN_SENT)

Client收到synack后回復(fù)ack給server。

server端處理流程: tcp_check_req--->syn_recv_sock-->tcp_v4_syn_recv_sock

if(sk_acceptq_is_full(sk)

goto exit_overflow;

如果server端設(shè)置了sysctl_tcp_abort_on_overflow,那么server會發(fā)送rst給client,并刪除掉這個鏈接;否則server端只是記錄一下LINUX_MIB_LISTENOVERFLOWS(詳見附錄2),然后返回。默認情況下是不會設(shè)置的,server端只是標記連接請求塊的acked標志,之后連接建立定時器,會遍歷半連接表,重新發(fā)送synack,重復(fù)上面的過程(具體的函數(shù)是inet_csk_reqsk_queue_prune),如果重傳次數(shù)超過synack重傳的閥值(/proc/sys/net/ipv4/tcp_synack_retries),會把該連接從半連接鏈表中刪除。

一次異常問題分析

Nginx通過FASTCGI協(xié)議連接cgi程序,出現(xiàn)cgi程序read讀取socket內(nèi)容的時候永遠block。通過netstat查看,cgi程序所在的服務(wù)器上顯示連接存在,但是nginx所在的服務(wù)器上顯示不存在該連接。

下面是原始數(shù)據(jù)圖:

我們從上面的數(shù)據(jù)流來分析一下:

出現(xiàn)問題的時候,cgi程序(tcp server端)處理非常慢,導(dǎo)致大量的連接請求放到accept隊列,把accept隊列阻塞。

148021 nginx(tcp client端) 連接cgi程序,發(fā)送syn

此時server端accpet隊列已滿,并且inet_csk_reqsk_queue_yong(sk) > 1,server端直接丟棄該數(shù)據(jù)包

148840 client端等待3秒后,重傳SYN

此時server端狀態(tài)與之前送變化,仍然丟棄該數(shù)據(jù)包

150163 client端又等待6秒后,重傳SYN

此時server端accept隊列仍然是滿的,但是存在了重傳握手的連接請求,server端接受連接請求,并發(fā)送synack給client端(150164)

150166 client端收到synack,標記本地連接為ESTABLISHED狀態(tài),給server端應(yīng)答ack,connect系統(tǒng)調(diào)用完成。

Server收到ack后,嘗試將連接放到accept隊列,但是因為accept隊列已滿,所以只是標記連接為acked,并不會將連接移動到accept隊列中,也不會為連接分配sendbuf和recvbuf等資源。

150167 client端的應(yīng)用程序,檢測到connect系統(tǒng)調(diào)用完成,開始向該連接發(fā)送數(shù)據(jù)。

Server端收到數(shù)據(jù)包,由于acept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

150225 client端由于沒有收到剛才發(fā)送數(shù)據(jù)的ack,所以會重傳剛才的數(shù)據(jù)包

150296 同上

150496 同上

150920 同上

151112 server端連接建立定時器生效,遍歷半連接鏈表,發(fā)現(xiàn)剛才acked的連接,重新發(fā)送synack給client端。

151113 client端收到synack后,根據(jù)ack值,使用SACK算法,只重傳最后一個ack內(nèi)容。

Server端收到數(shù)據(jù)包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

151896 client端等待3秒后,沒有收到對應(yīng)的ack,認為之前的數(shù)據(jù)包也丟失,所以重傳之前的內(nèi)容數(shù)據(jù)包。

152579 server端連接建立定時器生效,遍歷半連接鏈表,發(fā)現(xiàn)剛才acked的連接,synack重傳次數(shù)在閥值以內(nèi),重新發(fā)送synack給client端。

152581 cient端收到synack后,根據(jù)ack值,使用SACK算法,只重傳最后一個ack內(nèi)容。

Server端收到數(shù)據(jù)包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回

153455 client端等待3秒后,沒有收到對應(yīng)的ack,認為之前的數(shù)據(jù)包也丟失,所以重傳之前的內(nèi)容數(shù)據(jù)包。

155399 server端連接建立定時器生效,遍歷半連接鏈表,發(fā)現(xiàn)剛才acked的連接,synack重傳次數(shù)在閥值以內(nèi),重新發(fā)送synack給client端。

155400 cient端收到synack后,根據(jù)ack值,使用SACK算法,只重傳最后一個ack內(nèi)容。

Server端收到數(shù)據(jù)包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

156468 client端等待幾秒后,沒有收到對應(yīng)的ack,認為之前的數(shù)據(jù)包也丟失,所以重傳之前的內(nèi)容數(shù)據(jù)包。

161309 server端連接建立定時器生效,遍歷半連接鏈表,發(fā)現(xiàn)剛才acked的連接,synack重傳次數(shù)在閥值以內(nèi),重新發(fā)送synack給client端。[!--empirenews.page--]

161310 cient端收到synack后,根據(jù)ack值,使用SACK算法,只重傳最后一個ack內(nèi)容。

Server端收到數(shù)據(jù)包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

162884 client端等待幾秒后,沒有收到對應(yīng)的ack,認為之前的數(shù)據(jù)包也丟失,所以重傳之前的內(nèi)容數(shù)據(jù)包。

Server端收到數(shù)據(jù)包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

164828 client端等待一段時間后,認為連接不可用,于是發(fā)送FIN、ACK給server端。Client端的狀態(tài)變?yōu)镕IN_WAIT1,等待一段時間后,client端將看不到該鏈接。

164829 server端收到ACK后,此時cgi程序處理完一個請求,從accept隊列中取走一個連接,此時accept隊列中有了空閑,server端將請求的連接放到accept隊列中。

這樣cgi所在的服務(wù)器上顯示該鏈接是established的,但是nginx(client端)所在的服務(wù)器上已經(jīng)沒有該鏈接了。

之后,當cgi程序從accept隊列中取到該連接后,調(diào)用read去讀取sock中的內(nèi)容,但是由于client端早就退出了,所以read就會block那里了。

問題解決

或許你會認為在164829中,server端不應(yīng)該建立連接,這是內(nèi)核的bug。但是內(nèi)核是按照RFC來實現(xiàn)的,在3次握手的過程中,是不會判斷FIN標志位的,只會處理SYN、ACK、RST這三種標志位。

從應(yīng)用層的角度來考慮解決問題的方法,那就是使用非阻塞的方式read,或者使用select超時方式read;亦或者nginx中關(guān)閉連接的時候使用RST方式,而不是FIN方式。

附錄1

when I use linux TCP socket, and find there is a bug in function sk_acceptq_is_full():

When a new SYN comes, TCP module first checks its validation. If valid,send SYN,ACK to the client and add the sock

to the syn hash table.

Next time if received the valid ACK for SYN,ACK from the client. server will accept this connection and increase the

sk->sk_ack_backlog -- which is done in function tcp_check_req().

We check wether acceptq is full in function tcp_v4_syn_recv_sock().

Consider an example:

After listen(sockfd, 1) system call, sk->sk_max_ack_backlog is set to

As we know, sk->sk_ack_backlog is initialized to 0. Assuming accept() system call is not invoked now

1. 1st connection comes. invoke sk_acceptq_is_full(). sk->sk_ack_backlog=0 sk->sk_max_ack_backlog=1, function return 0 accept this connection. Increase the sk->sk_ack_backlog

2. 2nd connection comes. invoke sk_acceptq_is_full(). sk->sk_ack_backlog=1 sk->sk_max_ack_backlog=1, function return 0 accept this connection. Increase the sk->sk_ack_backlog

3. 3rd connection comes. invoke sk_acceptq_is_full(). sk->sk_ack_backlog=2 sk->sk_max_ack_backlog=1, function return 1. Refuse this connection.I think it has bugs. after listen system call. sk->sk_max_ack_backlog=1

but now it can accept 2 connections.

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

上海2025年9月5日 /美通社/ -- 由紐倫堡會展(上海)有限公司舉辦的上海國際嵌入式會議將于 2025 年 10 月 16-17 日在上海世博展覽館舉辦。 此次會議將由三個版塊組成:嵌入式技術(shù)會議、汽...

關(guān)鍵字: 嵌入式 CE CHINA EMBEDDED

-DXC通過初創(chuàng)企業(yè)合作推動汽車與制造業(yè)AI創(chuàng)新 初創(chuàng)企業(yè)Acumino、CAMB.AI與GreenMatterAI合作將AI創(chuàng)新推向市場 合作源于DXC與STARTUP AUTOBAHN的伙伴關(guān)系 弗吉尼亞州阿什...

關(guān)鍵字: 汽車 AI AN AC

CPU親和度通過限制進程或線程可以運行的CPU核心集合,使得它們只能在指定的CPU核心上執(zhí)行。這可以減少CPU緩存的失效次數(shù),提高緩存命中率,從而提升系統(tǒng)性能。

關(guān)鍵字: Linux 嵌入式

在Linux系統(tǒng)性能優(yōu)化中,內(nèi)存管理與網(wǎng)絡(luò)連接處理是兩大核心領(lǐng)域。vm.swappiness與net.core.somaxconn作為關(guān)鍵內(nèi)核參數(shù),直接影響系統(tǒng)在高負載場景下的穩(wěn)定性與響應(yīng)速度。本文通過實戰(zhàn)案例解析這兩個...

關(guān)鍵字: Linux 內(nèi)存管理

臺北2025年8月8日 /美通社/ -- 作為專業(yè)伺服器設(shè)計與制造商,神達控股股份有限公司(股票代號:3706)旗下子公司神雲(yún)科技股份有限公司(MiTAC Computing Technology Corporation...

關(guān)鍵字: MIT AI AC BSP

多款高性能平臺登場,以快速響應(yīng)服務(wù)能力滿足中國多元化市場需求 上海2025年7月26日 /美通社/ -- 世界人工智能大會訊—神雲(yún)科技股份有限公司(MiTAC Computing Technology Cor...

關(guān)鍵字: AI 數(shù)據(jù)中心 IC AC

對于LLM,我使用b谷歌Gemini的免費層,所以唯一的成本是n8n托管。在使用了n8n Cloud的免費積分后,我決定將其托管在Railway上(5美元/月)。然而,由于n8n是開源的,您可以在自己的服務(wù)器上托管它,而...

關(guān)鍵字: 人工智能 n8n Linux

在Linux系統(tǒng)管理中,權(quán)限控制是安全運維的核心。本文通過解析/etc/sudoers文件配置與組策略的深度應(yīng)用,結(jié)合某金融企業(yè)生產(chǎn)環(huán)境案例(成功攔截98.7%的非法提權(quán)嘗試),揭示精細化權(quán)限管理的關(guān)鍵技術(shù)點,包括命令別...

關(guān)鍵字: Linux 用戶權(quán)限 sudoers文件

Linux內(nèi)核中的信號量(Semaphore)是一種用于資源管理的同步原語,它允許多個進程或線程對共享資源進行訪問控制。信號量的主要作用是限制對共享資源的并發(fā)訪問數(shù)量,從而防止系統(tǒng)過載和數(shù)據(jù)不一致的問題。

關(guān)鍵字: Linux 嵌入式

在云計算與容器化技術(shù)蓬勃發(fā)展的今天,Linux網(wǎng)絡(luò)命名空間(Network Namespace)已成為構(gòu)建輕量級虛擬網(wǎng)絡(luò)的核心組件。某頭部互聯(lián)網(wǎng)企業(yè)通過命名空間技術(shù)將測試環(huán)境資源消耗降低75%,故障隔離效率提升90%。本...

關(guān)鍵字: Linux 云計算
關(guān)閉