新聞中心
在Linux系統(tǒng)中,TCP socket綁定端口(bind)的操作是非常常見(jiàn)的。然而,有時(shí)候我們希望在綁定新端口之前關(guān)閉當(dāng)前正在使用的端口連接,以確保新的TCP連接正常工作。本文將介紹如何在Linux系統(tǒng)中實(shí)現(xiàn)此操作。

通榆網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),通榆網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為通榆上千多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的通榆做網(wǎng)站的公司定做!
1. 使用SO_REUSEADDR選項(xiàng)
SO_REUSEADDR選項(xiàng)可以讓我們?cè)诮壎ㄐ碌亩丝谥?,先關(guān)閉當(dāng)前端口連接。在使用SO_REUSEADDR選項(xiàng)時(shí),我們需要注意以下幾點(diǎn):
– 該選項(xiàng)需要在socket創(chuàng)建時(shí)就設(shè)置,因此我們需要使用setsockopt函數(shù)設(shè)置該選項(xiàng):
“`
int on = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))
perror(“setsockopt”);
exit(1);
}
“`
– 在使用SO_REUSEADDR選項(xiàng)時(shí),close函數(shù)并不會(huì)立即關(guān)閉socket連接,而是將其標(biāo)記為“等待連接中”。因此,我們需要使用shutdown函數(shù)主動(dòng)關(guān)閉連接:
“`
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
“`
– 在調(diào)用shutdown函數(shù)之前,需要確保socket已經(jīng)完成了初始化等操作,否則可能會(huì)導(dǎo)致程序異常退出。
– 如果我們正在監(jiān)聽(tīng)一個(gè)端口,那么在使用SO_REUSEADDR選項(xiàng)時(shí)可能會(huì)遇到“端口忙”的問(wèn)題。此時(shí),我們可以使用SO_REUSEPORT選項(xiàng)解決:
“`
int on = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &on, sizeof(on))
perror(“setsockopt”);
exit(1);
}
“`
2. 使用bind函數(shù)的SO_EXCLUSIVEADDRUSE選項(xiàng)
SO_EXCLUSIVEADDRUSE選項(xiàng)可以確保在綁定新端口之前,當(dāng)前端口連接已經(jīng)關(guān)閉。使用SO_EXCLUSIVEADDRUSE選項(xiàng)時(shí),我們需要注意以下幾點(diǎn):
– 該選項(xiàng)需要在bind函數(shù)中設(shè)置,因此我們需要使用bind函數(shù)的第三個(gè)參數(shù)(struct sockaddr *addr)來(lái)設(shè)置該選項(xiàng):
“`
int on = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &on, sizeof(on))
perror(“setsockopt”);
exit(1);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr*)&addr, sizeof(addr))
perror(“bind”);
exit(1);
}
“`
– 由于在調(diào)用setsockopt函數(shù)后必須緊接著調(diào)用bind函數(shù),因此在使用SO_EXCLUSIVEADDRUSE選項(xiàng)時(shí),我們不能使用listen函數(shù)來(lái)監(jiān)聽(tīng)socket,否則程序可能會(huì)在setsockopt函數(shù)返回之前就退出。
– 使用SO_EXCLUSIVEADDRUSE選項(xiàng)時(shí),即使連接已經(jīng)關(guān)閉,bind函數(shù)也可能會(huì)返回EADDRINUSE錯(cuò)誤。此時(shí),我們可以使用SO_REUSEADDR選項(xiàng)。另外,有些Linux內(nèi)核版本需要在sysctl中修改net.ipv4.tcp_tw_reuse參數(shù),才能正常使用SO_REUSEADDR選項(xiàng)。
本文介紹了在Linux系統(tǒng)中實(shí)現(xiàn)TCP重新綁定端口前先關(guān)閉連接的兩種方法。使用SO_REUSEADDR選項(xiàng)比較簡(jiǎn)單,但是需要注意一些細(xì)節(jié)問(wèn)題;使用SO_EXCLUSIVEADDRUSE選項(xiàng)比較靈活,可以確保當(dāng)前端口連接已經(jīng)關(guān)閉,但是需要更多的配置和控制。在具體使用時(shí),我們應(yīng)該根據(jù)實(shí)際應(yīng)用場(chǎng)景來(lái)選擇合適的方法。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián)為您提供網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù)!
暢談linux下TCP(上)
tcp 協(xié)議 是互聯(lián)網(wǎng)中最常用的協(xié)議 , 開(kāi)發(fā)人員基本上天天和它打交道,對(duì)它進(jìn)行深入了解。 可以幫助我們排查定位bug和進(jìn)行程序優(yōu)化。下面我將就TCP幾個(gè)點(diǎn)做深入的探討
客戶端:收到 ack 后 分配連接資源。 發(fā)送數(shù)據(jù)
服務(wù)器 : 收到 syn 后立即 分配連接資源
客戶端:收到ACK, 立即分配資源
服務(wù)器:收到ACK, 立即分配資源
既然三次握手也液銀顫不是100%可靠, 那四次,五次,六次。呢? 其實(shí)都一樣,不管多少次都有丟包問(wèn)題。
client 只發(fā)送一個(gè) SYN, server 分配一個(gè)tcb, 放入syn隊(duì)列中。 這時(shí)候連接叫
半連接
狀態(tài);如果server 收不到 client 的ACK, 會(huì)不停重試 發(fā)送 ACK-SYN 給client 。重試間隔 為 2 的 N 次方 疊加(2^0 , 2^1, 2^2 ….);直至超時(shí)才釋放syn隊(duì)列中的這個(gè) TCB;
在半連接狀態(tài)下, 一方面會(huì)占用隊(duì)列配額資源,另一方面占用內(nèi)存資源。我們應(yīng)該讓半連接狀態(tài)存在時(shí)間盡可能的小
當(dāng)client 向一個(gè)未打開(kāi)的端口發(fā)起連接請(qǐng)求時(shí),會(huì)收到一個(gè)RST回復(fù)包
當(dāng)listen 的 backlog 和 somaxconn 都設(shè)置了得時(shí)候, 取兩者min值
Recv-Q 是accept 隊(duì)列當(dāng)前個(gè)數(shù), Send-Q 設(shè)置更大值
這種SYN洪水攻擊是一種常見(jiàn)攻擊方式,就是利用半連接隊(duì)列特性,占滿syn 隊(duì)列的 資源,導(dǎo)致 client無(wú)法連接上。
解決方案:
為什么不像握手那樣合并成三次揮手? 因?yàn)楹蛣傞_(kāi)始連接情況,連接是大家都從0開(kāi)始, 關(guān)閉時(shí)有歷史包袱的。server(被動(dòng)關(guān)閉方) 收到 client(主動(dòng)關(guān)閉方) 的關(guān)閉請(qǐng)求FIN包。 這時(shí)候可能還有未發(fā)送完的數(shù)據(jù),不能丟棄。 所以需要分開(kāi)。事實(shí)可能是這樣
當(dāng)然,在沒(méi)有待發(fā)數(shù)據(jù),并且允許 Delay ACK 情況下, FIN-ACK合并還是非常常見(jiàn)的事情,這是三次揮手是可以的。
同上
CLOSE_WAIT 是被動(dòng)關(guān)閉方才有的狀態(tài)
。
被動(dòng)關(guān)閉方 到 期間的狀態(tài)為 CLOSE_WAIT, 這個(gè)狀態(tài)仍然能發(fā)鬧敗送數(shù)據(jù)。 我們叫做
半關(guān)閉
, 下面用個(gè)例子來(lái)分析:
這個(gè)是我實(shí)際生產(chǎn)環(huán)境碰到的一個(gè)問(wèn)題,長(zhǎng)連接會(huì)話場(chǎng)景,server端收到client的rpc call 請(qǐng)求1,處理發(fā)現(xiàn)請(qǐng)求包有問(wèn)題,就強(qiáng)制關(guān)閉結(jié)束這次會(huì)話, 但是 因?yàn)閏lient 發(fā)送 第二次請(qǐng)求之前,并沒(méi)有去調(diào)用recv,所以并不知道 這個(gè)連接被server關(guān)閉, 繼續(xù)發(fā)送 請(qǐng)求2 , 此時(shí)是半連接,能夠成功發(fā)送到對(duì)端機(jī)器,但是recv結(jié)果后,搏兆遇到連接已經(jīng)關(guān)閉錯(cuò)誤。
如果 client 和 server 恰好同時(shí)發(fā)起關(guān)閉連接。這種情況下,兩邊都是主動(dòng)連接,都會(huì)進(jìn)入 TIME_WAIT狀態(tài)
1、
被動(dòng)關(guān)閉方在LAST_ACK狀態(tài)(已經(jīng)發(fā)送FIN),等待主動(dòng)關(guān)閉方的ACK應(yīng)答,但是 ACK丟掉, 主動(dòng)方并不知道,以為成功關(guān)閉。因?yàn)闆](méi)有TIME_WAIT等待時(shí)間,可以立即創(chuàng)建新的連接, 新的連接發(fā)送SYN到前面那個(gè)未關(guān)閉的被動(dòng)方,被動(dòng)方認(rèn)為是收到錯(cuò)誤指令,會(huì)發(fā)送RST。導(dǎo)致創(chuàng)建連接失敗。
2、
主動(dòng)關(guān)閉方斷開(kāi)連接,如果沒(méi)有TIME_WAIT等待時(shí)間,可以馬上建立一個(gè)新的連接,但是前一個(gè)已經(jīng)斷開(kāi)連接的,延遲到達(dá)的數(shù)據(jù)包。 被新建的連接接收,如果剛好seq 和 ack字段 都正確, seq在滑動(dòng)窗口范圍內(nèi)(只能說(shuō)機(jī)率非常小,但是還是有可能會(huì)發(fā)生),會(huì)被當(dāng)成正確數(shù)據(jù)包接收,導(dǎo)致數(shù)據(jù)串包。 如果不在window范圍內(nèi),則沒(méi)有影響( 發(fā)送一個(gè)確認(rèn)報(bào)文(ack 字段為期望ack的序列號(hào),seq為當(dāng)前發(fā)送序列號(hào)),狀態(tài)變保持原樣)
TIME_WAIT 問(wèn)題比較比較常見(jiàn),特別是CGI機(jī)器,并發(fā)量高,大量連接后段服務(wù)的tcp短連接。因此也衍生出了多種手段解決。雖然每種方法解決不是那么完美,但是帶來(lái)的好處一般多于壞處。還是在日常工作中會(huì)使用。
1、改短TIME_WAIT 等待時(shí)間
這個(gè)是之一個(gè)想到的解決辦法,既然等待時(shí)間太長(zhǎng),就改成時(shí)間短,快速回收端口。但是實(shí)際情況往往不樂(lè)觀,對(duì)于并發(fā)的機(jī)器,你改多短才能保證回收速度呢,有時(shí)候幾秒鐘就幾萬(wàn)個(gè)連接。太短的話,就會(huì)有前面兩種問(wèn)題小概率發(fā)生。
2、禁止Socket lingering
這種情況下關(guān)閉連接,會(huì)直接拋棄緩沖區(qū)中待發(fā)送的數(shù)據(jù),會(huì)發(fā)送一個(gè)RST給對(duì)端,相當(dāng)于直接拋棄TIME_WAIT, 進(jìn)入CLOSE狀態(tài)。同樣因?yàn)槿∠?TIME_WAIT 狀態(tài),會(huì)有前面兩種問(wèn)題小概率發(fā)生。
3、tcp_tw_reuse
net.ipv4.tcp_tw_reuse選項(xiàng)是 從 TIME_WAIT 狀態(tài)的隊(duì)列中,選取條件:1、remote 的 ip 和端口相同, 2、選取一個(gè)時(shí)間戳小于當(dāng)前時(shí)間戳; 用來(lái)解決端口不足的尷尬。
現(xiàn)在端口可以復(fù)用了,看看如何面對(duì)前面TIME_WAIT 那兩種問(wèn)題。 我們仔細(xì)回顧用一下前面兩種問(wèn)題。
都是在新建連接中收到老連接的包導(dǎo)致的問(wèn)題
, 那么如果我能在新連接中識(shí)別出此包為非法包,是不是就可以丟掉這些無(wú)用包,解決問(wèn)題呢。
需要實(shí)現(xiàn)這些功能,需要擴(kuò)展一下tcp 包頭。 增加 時(shí)間戳字段。 發(fā)送者 在每次發(fā)送的時(shí)候。 在tcp包頭里面帶上發(fā)送時(shí)候的時(shí)間戳。 當(dāng)接收者接收的時(shí)候,在ACK應(yīng)答中除了TCP包頭中帶自己此時(shí)發(fā)送的時(shí)間戳,并且把收到的時(shí)間戳附加在后面。也就是說(shuō)ACK包中有兩個(gè)時(shí)間戳字段。結(jié)構(gòu)如下:
那我們接下來(lái)一個(gè)個(gè)分析tcp_tw_reuse是如何解決TIME_WAIT的兩個(gè)問(wèn)題的
4、tcp_tw_recycle
tcp_tw_recycle 也是借助 timestamp機(jī)制。顧名思義, tcp_tw_reuse 是復(fù)用 端口,并不會(huì)減少 TIME-WAIT 數(shù)量。你去查詢機(jī)器上TIME-WAIT 數(shù)量,還是 幾千幾萬(wàn)個(gè),這點(diǎn)對(duì)有強(qiáng)迫癥的同學(xué)感覺(jué)很不舒服。tcp_tw_recycle 是 提前 回收 TIME-WAIT資源。會(huì)減少 機(jī)器上 TIME-WAIT 數(shù)量。
關(guān)于linux tcp 關(guān)閉再bind的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),香港虛擬主機(jī)被稱為香港虛擬空間/香港網(wǎng)站空間,或者簡(jiǎn)稱香港主機(jī)/香港空間。香港虛擬主機(jī)特點(diǎn)是免備案空間開(kāi)通就用, 創(chuàng)新互聯(lián)香港主機(jī)精選cn2+bgp線路訪問(wèn)快、穩(wěn)定!
網(wǎng)頁(yè)題目:LinuxTCP重新綁定端口前先關(guān)閉連接的方法(linuxtcp關(guān)閉再bind)
瀏覽路徑:http://www.dlmjj.cn/article/dhscghe.html


咨詢
建站咨詢
