設(shè)置
  • 日夜間
    隨系統(tǒng)
    淺色
    深色
  • 主題色

最多能創(chuàng)建多少個 TCP 連接?

低并發(fā)編程 2022/10/8 18:05:08 責(zé)編:云熙

本文來自微信公眾號:低并發(fā)編程 (ID:dibingfa),作者:閃客

我是一個 Linux 服務(wù)器上的進(jìn)程,名叫小進(jìn)。

老是有人說我最多只能創(chuàng)建 65535 個 TCP 連接。

我不信這個邪,今天我要親自去實踐一下。

我走到操作系統(tǒng)老大的跟前,說:

"老操,我要建立一個 TCP 連接!"

老操不慌不忙,拿出一個表格遞給我,"小進(jìn),先填表吧"

我一看這個表,這不就是經(jīng)典的 socket 四元組嘛。我只有一塊網(wǎng)卡,其 IP 地址是 123.126.45.68,我想要與 110.242.68.3 的 80 端口建立一個 TCP 連接,我將這些信息填寫在了表中。

源端口號填什么呢?我記得端口號是 16 位的,可以有 0 ~ 65535 這個范圍的數(shù)字,那我隨便選一個吧!

正當(dāng)我猶豫到底選什么數(shù)字的時候,老操一把搶過我的表格。

"你墨跡個啥呢小進(jìn)?源端口號不用你填,我會給你分配一個可用的數(shù)字。源 IP 也不用你填,我知道都有哪些網(wǎng)卡,并且會幫你選個合適的。真是個新手,回去等消息吧。"

"哦"

老操帶著我的表格,走了。

過了很長時間,老操終于回來了,并且?guī)е粋€紙條。

"小進(jìn),你把這個收好了。"

我問道,"這是啥呀?"

老操不耐煩地說道,"剛剛說你是新手你還不服,這個 5 表示文件描述符,linux 下一切皆文件,你待會和你那個目標(biāo) IP 進(jìn)行 TCP 通信的時候,就對著這個文件描述符讀寫就好啦。"

"這么方便!好的,謝謝老操。"

我拿著這個文件描述符,把它放到屬于我的內(nèi)存中裱起來了,反正我只是想看看最多能創(chuàng)建多少 TCP 連接,又不是去真的用它,嘻嘻。

端口號

過了一分鐘,我又去找老操了。

"老操,我要建立一個 TCP 連接!"

老操不慌不忙,拿出一個表格遞給我,"小進(jìn),先填表吧"

這回我熟悉了,只把目標(biāo) IP 和目標(biāo)端口填好。

老操辦好事之后,又帶著一個紙條回來,上面寫著數(shù)字 "6"。

就這樣,我每隔一分鐘都去找老操建立一個新的 TCP 連接,目標(biāo) IP 都是 110.242.68.3,目標(biāo)端口都是 80。

老操也很奇怪,不知道我在這折騰啥,他雖然權(quán)力大,但無權(quán)拒絕我的指令,每次都兢兢業(yè)業(yè)地把事情辦好,并給我一張一張寫著文件描述符的紙條。

直到有一次,我收到的紙條有些不同。

我?guī)е┰S責(zé)怪的語氣問,"老操,這是怎么回事呀?"

老操也沒好氣地說,"這表示端口號不夠用啦!早就覺得你小子不對勁了,一個勁地對著同一個 IP 和端口創(chuàng)建 TCP 連接,之前沒辦法必須執(zhí)行你給的指令,現(xiàn)在不行了,端口號不夠用了,源端口那里我沒法給你填了。"

我也不是那么好騙的,質(zhì)疑道。"老操,你也別欺負(fù)我這個新手,我可是知道端口號是 16 位的,范圍是 1~65535,一共可以創(chuàng)建 65535 個 TCP 連接,我現(xiàn)在才創(chuàng)建了 63977 個,怎么就不夠了!"

老操鄙視地看了我一眼,"你小子可真是閑的蛋疼啊,還真一個個數(shù),來我告訴你吧,Linux 對可使用的端口范圍是有具體限制的,具體可以用如下命令查看。"

[root]# cat /proc/sys/net/ipv4/ip_local_port_range 
1024 65000

"看到?jīng)],當(dāng)前的限制是 1024~65000,所以你就只能有 63977 個端口號可以使用。"

我趕緊像老操道歉,"哎喲真是抱歉,還是我見識太少,那這個數(shù)可以修改么?"

老操也沒跟我一般見識,還是耐心地回答我,"可以的,具體可以 vim /etc/ sysctl.conf 這個文件進(jìn)行修改,我們在這個文件里添加一行記錄"

net.ipv4.ip_local_port_range = 60000 60009

"保存好后執(zhí)行 sysctl -p /etc/ sysctl.conf 使其生效。這樣你就只有 10 個端口號可以用了,就會更快報出端口號不夠用的錯誤"

"原來如此,謝謝老操又給我上了一課。"

哎不對,建立一個 TCP 連接,需要將通信兩端的套接字(socket)進(jìn)行綁定,如下:

源 IP 地址:源端口號 <---->  目標(biāo) IP 地址:目標(biāo)端口號

只要這套綁定關(guān)系構(gòu)成的四元組不重復(fù)即可,剛剛端口號不夠用了,是因為我一直對同一個目標(biāo) IP 和端口建立連接,那我換一個目標(biāo)端口號試試。

我又把這個表交給老操,老操一眼就看破了我的小心思,可是也沒辦法,馬上去給我建立了一個新的 TCP 連接,并且成功返回給我一個新的文件描述符紙條。

看來成功了,只要源端口號不用夠用了,就不斷變換目標(biāo) IP 和目標(biāo)端口號,保證四元組不重復(fù),我就能創(chuàng)建好多好多 TCP 連接啦!

這也證明了有人說最多只能創(chuàng)建 65535 個 TCP 連接是多么荒唐。

文件描述符

找到了突破端口號限制的辦法,我不斷找老操建立 TCP 連接,老操也拿我沒有辦法。

直到有一次,我又收到了一張?zhí)厥獾募垪l,上面寫的不是文件描述符。

我又沒好氣地問老操,"這又是咋回事?"

老操幸災(zāi)樂禍地告訴我,"呵呵,你小子以為突破端口號限制就無法無天了?現(xiàn)在文件描述符不夠用啦!"

"怎么啥啥都有限制啊?你們操作系統(tǒng)給我們的限制也太多了吧?"

"廢話,你看看你都建了多少個 TCP 連接了!每建立一個 TCP 連接,我就得分配給你一個文件描述符,linux 對可打開的文件描述符的數(shù)量分別作了三個方面的限制。"

系統(tǒng)級:當(dāng)前系統(tǒng)可打開的最大數(shù)量,通過 cat /proc/ sys / fs / file-max 查看

用戶級:指定用戶可打開的最大數(shù)量,通過 cat /etc/ security / limits.conf 查看

進(jìn)程級:單個進(jìn)程可打開的最大數(shù)量,通過 cat /proc/ sys / fs / nr_open 查看

天呢,真是人在屋檐下呀,我趕緊看了看這些具體的限制。

[root ~]# cat /proc/sys/fs/file-max
100000
[root ~]# cat /proc/sys/fs/nr_open
100000
[root ~]# cat /etc/security/limits.conf

* soft nproc 100000
* hard nproc 100000

原來如此,我記得剛剛收到的最后一張紙條是。

再之后就收到文件描述符不夠的錯誤了。

我又請教老操,"老操,那這個限制可以修改么?"

老操仍然耐心地告訴我,"當(dāng)然可以,比如你想修改單個進(jìn)程可打開的最大文件描述符限制為 100,可以這樣。"

echo 100  /proc/sys/fs/nr_open

"原來如此,我這就去把各種文件描述符限制都改大一點,也不多,就在后面加個 0 吧"

"額,早知道不告訴你小子了。" 老操再次用鄙視的眼睛看著我。

線程

突破了文件描述符限制,我又開始肆無忌憚地創(chuàng)建起了 TCP 連接。

但我發(fā)現(xiàn),老操的辦事效率越來越慢,建立一個 TCP 連接花的時間越來越久。

有一次,我忍不住責(zé)問老操,"你是不是在偷懶啊?之前找你建一個 TCP 連接就花不到一分鐘時間,你看看最近我哪次不是等一個多小時你才搞好?"

老操也忍不住了,"小進(jìn)啊你還好意思說我,你知不知道你每建一個 TCP 連接都需要消耗一個線程來為你服務(wù)?現(xiàn)在我和 CPU 老大那里都忙得不可開交了,一直在為你這好幾十萬個線程不停地進(jìn)行上下文切換,我們精力有限啊,自然就沒法像以前那么快為你服務(wù)了。"

聽完老操的抱怨,我想起了之前似乎有人跟我說過 C10K 問題,就是當(dāng)服務(wù)器連接數(shù)達(dá)到 1 萬且每個連接都需要消耗一個線程資源時,操作系統(tǒng)就會不停地忙于線程的上下文切換,最終導(dǎo)致系統(tǒng)崩潰,這可不是鬧著玩的。

我趕緊像操作系統(tǒng)老大請教,"老操,實在不好意思,一直以為你強大無比,沒想到也有忙得不可開交的時候呀,那我們現(xiàn)在應(yīng)該怎么辦呀?"

老操無奈地說,"我勸你還是別再繼續(xù)玩了,沒什么意義,不過我想你也不會聽我的,那我跟你說兩句吧。"

你現(xiàn)在這種每建一個 TCP 連接就創(chuàng)建一個線程的方式,是最傳統(tǒng)的多線程并發(fā)模型,早期的操作系統(tǒng)也只支持這種方式。但現(xiàn)在我進(jìn)化了,我還支持 IO 多路復(fù)用的方式,簡單說就是一個線程可以管理多個 TCP 連接的資源,這樣你就可以用少量的線程來管理大量的 TCP 連接了。

我一臉疑惑,"啥是 IO 多路復(fù)用?。?。

老操一臉鄙視,"你這... 你去看看閃客的《你管這破玩意叫 IO 多路復(fù)用》,就明白了。"

這次真是大開眼界了,我趕緊把代碼改成了這種 IO 多路復(fù)用的模型,將原來的 TCP 連接銷毀掉,改成同一個線程管理多個 TCP 連接,很快,操作系統(tǒng)老大就恢復(fù)了以往的辦事效率,同時我的 TCP 連接數(shù)又多了起來。

內(nèi)存

突破了端口號、文件描述符、線程數(shù)等重重限制的我,再次肆無忌憚地創(chuàng)建起了 TCP 連接。

直到有一次,我又收到了一張紅牌。

嗨,又是啥東西限制了呀,改了不就完了。我不耐煩地問老操,"這回又是啥毛病?"

老操說道。"這個錯誤叫內(nèi)存溢出,每個 TCP 連接本身,以及這個連接所用到的緩沖區(qū),都是需要占用一定內(nèi)存的,現(xiàn)在內(nèi)存已經(jīng)被你占滿了,不夠用了,所以報了這個錯。"

我看這次老操特別耐心,也沒多說什么,但想著被內(nèi)存限制住了,有點不太開心,于是我讓老操幫我最后一個忙。

"老操呀,幫小進(jìn)我最后一個忙吧,你權(quán)利大,你看看把那些特別占內(nèi)存的進(jìn)程給殺掉,給我騰出點地方,我今天要完成我的夢想,看看 TCP 連接數(shù)到底能創(chuàng)建多少個!"

老操見我真的是夠拼的,便答應(yīng)了我,殺死了好多進(jìn)程,我很是感動。

CPU

有了老操為我爭取的內(nèi)存資源,我又開始日以繼日地創(chuàng)建 TCP 連接。

老操也不再說什么,同樣日以繼日地執(zhí)行著我的指令。

有一次,老操語重心長地對我說,"差不多了,我勸你就此收手吧,現(xiàn)在 CPU 的占用率已經(jīng)快到 100% 了。"

我覺得老操這人真的可笑,經(jīng)過這幾次的小挫折,我明白了只要思想不滑坡,方法總比苦難多,老操這人就是太謹(jǐn)慎了,我豈能半途而廢,不管他。

我仍然繼續(xù)創(chuàng)建著 TCP 連接。

直到有一天,老操把我請到一個小飯館,一塊吃了頓飯,吃好后說道。"咱哥倆也算是配合了很久啦,今天我是來跟你道個別的。"

我很不解地問,"怎么了老操,發(fā)生什么事了?。"

老操說,"由于你的 TCP 連接,CPU 占用率已經(jīng)很長時間維持在 100%,我們的使用者,也就是我們的上帝,幾乎什么事情都做不了了,連鼠標(biāo)動一下都要等好久,所以他給我下達(dá)了一個重啟的指令,我執(zhí)行這個指令后,你,以及像你一樣的所有進(jìn)程,包括我這個操作系統(tǒng)本身,一切都就消失了。"

我大驚失色,"啊,這么突然么?這條指令什么時候執(zhí)行?"

老操緩緩起身,"就現(xiàn)在了,剛剛這條指令還沒得到 CPU 運行的機會,不過現(xiàn)在到了。"

突然,我眼前一黑,一切都沒了。

總結(jié)

資源

一臺 Linux 服務(wù)器的資源

一個 TCP 連接占用的資源

占滿了會發(fā)生什么

CPU

看你花多少錢買的

看你用它干嘛

電腦卡死

內(nèi)存

看你花多少錢買的

取決于緩沖區(qū)大小

OOM

臨時端口號

ip_local_port_range

1

cannot assign requested address

文件描述符

fs.file-max

1

too many open files

進(jìn)程 \ 線程數(shù)

ulimit -n

看 IO 模型

系統(tǒng)崩潰

后記

其實這個問題,我覺得結(jié)論不重要,最重要的是思考過程。

而思考過程其實相當(dāng)簡單,就是,尋找限制條件而已,其實一開始這篇文章,我寫了個故事在開頭,但后來感覺放在后記更合適。故事是這樣的。

閃客:小宇,我問你,你一天最多能吃多少個漢堡?

小宇:額,你這問的太隱私了吧,不過看在你教我技術(shù)的份上,我就告訴你,最多能吃 4 個左右吧。

閃客:咳咳真的么?好吧,那你一分鐘最多能吃多少個漢堡?

小宇:快的話可能 2 個,不過正常應(yīng)該最多就能吃完 1 個了。

閃客:好的,那我問你,剛剛這兩個問題你為什么能不假思索地回答出來呢?

小宇:哈哈你這是什么話,我自己我當(dāng)然了解了。

閃客:不,你仔細(xì)想想你回答這兩個問題的邏輯。

小宇:哦我明白你的意思了,當(dāng)你問我一天最多能吃多少個漢堡時,我考慮的是我的胃的容量最多能容下多少個漢堡。而當(dāng)你問我一分鐘最多能吃多少個漢堡時,我考慮的時我吃漢堡的速度,按照這個速度在一分鐘內(nèi)能吃多少。

閃客:沒錯,你總結(jié)得很好!一天最多吃多少個漢堡,此時時間非常充裕,所以主要是胃的容量限制了這個漢堡最大值,計算公式應(yīng)該是:

最多漢堡數(shù) = 胃的容量 ÷ 漢堡的體積

而一分鐘最多吃多少個漢堡,此時胃的容量非常充裕,限制漢堡最大值的是時間因素,計算公式是:

最多漢堡數(shù) = 一分鐘 ÷ 吃一個漢堡的耗時

所以,取決于最先觸達(dá)的那個限制條件。

而最大 TCP 連接數(shù)這個問題,假如面試被問到了,即使你完全不會,也應(yīng)該有這樣的思路。

而如果你有了這樣的思路,你多多少少都能回答出讓面試官滿意的答案,因為計算機很多時候,更看重思路,而不是細(xì)枝末節(jié)。

廣告聲明:文內(nèi)含有的對外跳轉(zhuǎn)鏈接(包括不限于超鏈接、二維碼、口令等形式),用于傳遞更多信息,節(jié)省甄選時間,結(jié)果僅供參考,IT之家所有文章均包含本聲明。

相關(guān)文章

關(guān)鍵詞:Linux,linux

軟媒旗下網(wǎng)站: IT之家 最會買 - 返利返現(xiàn)優(yōu)惠券 iPhone之家 Win7之家 Win10之家 Win11之家

軟媒旗下軟件: 軟媒手機APP應(yīng)用 魔方 最會買 要知