端口選擇
繼續(xù)看inet_csk_get_port函數(shù):
在端口選擇前,先確定當(dāng)前該socket的“屬性”,即是否可以端口復(fù)用,是否在TCP_LISTEN狀態(tài),以便后面插入到桶隊(duì)列時(shí)設(shè)置fastreuse字段。
bool reuse = sk- >sk_reuse && sk- >sk_state != TCP_LISTEN;
進(jìn)行端口選擇和綁定:
端口綁定分為兩種,一種指定端口,一種隨機(jī)選擇。如果給 bind 傳 遞的地址參數(shù)中,port 字段為 0,那么就會自動選擇參數(shù)。
如代碼所示,當(dāng)端口port沒有指定時(shí),調(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實(shí)現(xiàn),重點(diǎn)看端口指定,暫時(shí)不看端口不指定(其實(shí)邏輯差不多)。那么當(dāng)用戶指定了端口,也就是port有值時(shí):
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端口號,計(jì)算哈希值,找到對應(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鏈表時(shí),找到了指定port相同的桶結(jié)構(gòu),則跳轉(zhuǎn)到tb_found:
if (net_eq(ib_net(tb), net) && tb- >port == port)
goto tb_found;
- 4、在tb_found標(biāo)簽中:判斷該桶結(jié)構(gòu)中sock隊(duì)列是否為空,為空且當(dāng)前套接字支持復(fù)用,則綁定成功。進(jìn)入success標(biāo)簽。
- 5、在succeess完成對該port對應(yīng)的桶結(jié)構(gòu)的初始化或修改
- 6、如果在3、中沒有找到對應(yīng)的桶結(jié)構(gòu),進(jìn)入tb_not_found標(biāo)簽,在當(dāng)前的chain鏈表中創(chuàng)建一個(gè)新的桶結(jié)構(gòu),再進(jìn)行4、5操作:
tb_not_found:
tb = inet_bind_bucket_create(hinfo- >bind_bucket_cachep,
net, head, port);
if (!tb)
goto fail_unlock;
端口復(fù)用的解釋
還是要從文章開頭的圖說起,bind時(shí)端口號都會經(jīng)過哈希計(jì)算分配在【相應(yīng)的哈希桶結(jié)構(gòu)inet_bind_hashbucket】上的chain鏈表節(jié)點(diǎn)的【桶結(jié)構(gòu)inet_bind_bucket上】,inet_bind_bucket 結(jié)構(gòu)就是用來描述端口和 sock 之間的綁定關(guān)系的。它的 port 字段表示一個(gè)綁定的端口,而 owners 則表示綁定到這個(gè)端口之上的所有 sock,因?yàn)槎丝诳梢灾赜?,所以同一端口可能有多個(gè) sock 綁定。
bind端口復(fù)用的實(shí)際用途基本上也就是:
防止服務(wù)器重啟時(shí)之前綁定的端口還未釋放或者程序突然退出而系統(tǒng)沒有釋放端口。這種情況下如果設(shè)定了端口復(fù)用,則新啟動的服務(wù)器進(jìn)程可以直接綁定端口。如果沒有設(shè)定端口復(fù)用,綁定會失敗,提示ADDR已經(jīng)在使用中!
-
Linux
+關(guān)注
關(guān)注
87文章
11161瀏覽量
208466 -
端口
+關(guān)注
關(guān)注
4文章
934瀏覽量
31945 -
Bind
+關(guān)注
關(guān)注
0文章
5瀏覽量
7594
發(fā)布評論請先 登錄
相關(guān)推薦
評論