端口選擇
繼續(xù)看inet_csk_get_port函數(shù):
在端口選擇前,先確定當前該socket的“屬性”,即是否可以端口復(fù)用,是否在TCP_LISTEN狀態(tài),以便后面插入到桶隊列時設(shè)置fastreuse字段。
bool reuse = sk- >sk_reuse && sk- >sk_state != TCP_LISTEN;
進行端口選擇和綁定:
端口綁定分為兩種,一種指定端口,一種隨機選擇。如果給 bind 傳 遞的地址參數(shù)中,port 字段為 0,那么就會自動選擇參數(shù)。
如代碼所示,當端口port沒有指定時,調(diào)用inet_csk_find_open_port(sk, &tb, &port):
if (!port) {
head = inet_csk_find_open_port(sk, &tb, &port);
if (!head)
return ret;
if (!tb)
goto tb_not_found;
goto success;
}
主要邏輯在net_csk_find_open_port實現(xiàn),重點看端口指定,暫時不看端口不指定(其實邏輯差不多)。那么當用戶指定了端口,也就是port有值時:
head = &hinfo- >bhash[inet_bhashfn(net, port,hinfo- >bhash_size)];
inet_bind_bucket_for_each(tb, &head- >chain)
if (net_eq(ib_net(tb), net) && tb- >port == port)
goto tb_found;
tb_not_found:
tb = inet_bind_bucket_create(hinfo- >bind_bucket_cachep,
net, head, port);
if (!tb)
goto fail_unlock;
tb_found:
if (!hlist_empty(&tb- >owners)) {
if (sk- >sk_reuse == SK_FORCE_REUSE)
goto success;
if ((tb- >fastreuse > 0 && reuse) ||
sk_reuseport_match(tb, sk))
goto success;
if (inet_csk_bind_conflict(sk, tb, true, true))
goto fail_unlock;
}
- 1、通過指定的port端口號,計算哈希值,找到對應(yīng)的inet_bind_hashbucket:
head = &hinfo- >bhash[inet_bhashfn(net, port,hinfo- >bhash_size)];
- 2 、調(diào)用inet_bind_bucket_for_each遍歷該inet_bind_hashbucke中的chain鏈表
inet_bind_bucket_for_each(tb, &head- >chain)
- 3、如果遍歷chain鏈表時,找到了指定port相同的桶結(jié)構(gòu),則跳轉(zhuǎn)到tb_found:
if (net_eq(ib_net(tb), net) && tb- >port == port)
goto tb_found;
- 4、在tb_found標簽中:判斷該桶結(jié)構(gòu)中sock隊列是否為空,為空且當前套接字支持復(fù)用,則綁定成功。進入success標簽。
- 5、在succeess完成對該port對應(yīng)的桶結(jié)構(gòu)的初始化或修改
- 6、如果在3、中沒有找到對應(yīng)的桶結(jié)構(gòu),進入tb_not_found標簽,在當前的chain鏈表中創(chuàng)建一個新的桶結(jié)構(gòu),再進行4、5操作:
tb_not_found:
tb = inet_bind_bucket_create(hinfo- >bind_bucket_cachep,
net, head, port);
if (!tb)
goto fail_unlock;
端口復(fù)用的解釋
還是要從文章開頭的圖說起,bind時端口號都會經(jīng)過哈希計算分配在【相應(yīng)的哈希桶結(jié)構(gòu)inet_bind_hashbucket】上的chain鏈表節(jié)點的【桶結(jié)構(gòu)inet_bind_bucket上】,inet_bind_bucket 結(jié)構(gòu)就是用來描述端口和 sock 之間的綁定關(guān)系的。它的 port 字段表示一個綁定的端口,而 owners 則表示綁定到這個端口之上的所有 sock,因為端口可以重用,所以同一端口可能有多個 sock 綁定。
bind端口復(fù)用的實際用途基本上也就是:
防止服務(wù)器重啟時之前綁定的端口還未釋放或者程序突然退出而系統(tǒng)沒有釋放端口。這種情況下如果設(shè)定了端口復(fù)用,則新啟動的服務(wù)器進程可以直接綁定端口。如果沒有設(shè)定端口復(fù)用,綁定會失敗,提示ADDR已經(jīng)在使用中!
-
Linux
+關(guān)注
關(guān)注
88文章
11760瀏覽量
219033 -
端口
+關(guān)注
關(guān)注
4文章
1104瀏覽量
33966 -
Bind
+關(guān)注
關(guān)注
0文章
5瀏覽量
7827
發(fā)布評論請先 登錄
TCP server 不能 bind 80 端口?
Android內(nèi)核分析
基于Linux 2.6內(nèi)核Makefile分析
關(guān)于Linux 2.6內(nèi)核Makefile的分析
谷歌Android設(shè)備內(nèi)核引入主線Linux內(nèi)核難嗎?
Linux內(nèi)核GPIO操作函數(shù)的詳解分析
什么是bind?你真的熟悉bind嗎?
Linux bind的核心執(zhí)行函數(shù)
Linux內(nèi)核分析 端口哈希桶
Linux內(nèi)核分析 bind端口選擇
評論