Linux内核分析 bind端口选择

描述

端口选择

继续看inet_csk_get_port函数:

在端口选择前,先确定当前该socket的“属性”,即是否可以端口复用,是否在TCP_LISTEN状态,以便后面插入到桶队列时设置fastreuse字段。

bool reuse = sk- >sk_reuse && sk- >sk_state != TCP_LISTEN;

进行端口选择和绑定:

端口绑定分为两种,一种指定端口,一种随机选择。如果给 bind 传 递的地址参数中,port 字段为 0,那么就会自动选择参数。

如代码所示,当端口port没有指定时,调用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实现,重点看端口指定,暂时不看端口不指定(其实逻辑差不多)。那么当用户指定了端口,也就是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端口号,计算哈希值,找到对应的inet_bind_hashbucket:
head = &hinfo- >bhash[inet_bhashfn(net, port,hinfo- >bhash_size)];
  • 2 、调用inet_bind_bucket_for_each遍历该inet_bind_hashbucke中的chain链表
inet_bind_bucket_for_each(tb, &head- >chain)
  • 3、如果遍历chain链表时,找到了指定port相同的桶结构,则跳转到tb_found:
if (net_eq(ib_net(tb), net) && tb- >port == port)
   goto tb_found;
  • 4、在tb_found标签中:判断该桶结构中sock队列是否为空,为空且当前套接字支持复用,则绑定成功。进入success标签。
  • 5、在succeess完成对该port对应的桶结构的初始化或修改
  • 6、如果在3、中没有找到对应的桶结构,进入tb_not_found标签,在当前的chain链表中创建一个新的桶结构,再进行4、5操作:
tb_not_found:
 tb = inet_bind_bucket_create(hinfo- >bind_bucket_cachep,
         net, head, port);
 if (!tb)
  goto fail_unlock;

端口复用的解释

还是要从文章开头的图说起,bind时端口号都会经过哈希计算分配在【相应的哈希桶结构inet_bind_hashbucket】上的chain链表节点的【桶结构inet_bind_bucket上】,inet_bind_bucket 结构就是用来描述端口和 sock 之间的绑定关系的。它的 port 字段表示一个绑定的端口,而 owners 则表示绑定到这个端口之上的所有 sock,因为端口可以重用,所以同一端口可能有多个 sock 绑定。

bind端口复用的实际用途基本上也就是:

防止服务器重启时之前绑定的端口还未释放或者程序突然退出而系统没有释放端口。这种情况下如果设定了端口复用,则新启动的服务器进程可以直接绑定端口。如果没有设定端口复用,绑定会失败,提示ADDR已经在使用中!

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分