WEB开发网
开发学院软件开发Java tcp connection setup的实现(一) 阅读

tcp connection setup的实现(一)

 2009-09-10 00:00:00 来源:WEB开发网   
核心提示: 这里我先来介绍下inet_csk_get_port的流程. 当绑定的port为0时,这时也就是说需要kernel来分配一个新的port. 1 首先得到系统的port范围. 2 随机分配一个port. 3 从bhash中得到当前随机分配的端口的链表(也就是inet_bind_bucket链表).

这里我先来介绍下inet_csk_get_port的流程.

当绑定的port为0时,这时也就是说需要kernel来分配一个新的port.

1 首先得到系统的port范围.

2  随机分配一个port.

3 从bhash中得到当前随机分配的端口的链表(也就是inet_bind_bucket链表).

4 遍历这个链表(链表为空的话,也说明这个port没有被使用),如果这个端口已经被使用,则将端口号加一,继续循环,直到找到当前没有被使用的port,也就是没有在bhash中存在的port.

5 新建一个inet_bind_bucket,并插入到bhash中.

当指定port时.

1 从bhash中根据hash值(port计算的)取得当前指定端口对应的inet_bind_bucket结构.

2 如果bhash中存在,则说明,这个端口已经在使用,因此需要判断这个端口是否允许被reuse.

3 如果不存在,则步骤和上面的第5部一样.

Java代码

int inet_csk_get_port(struct sock *sk, unsigned short snum) 
{ 
 struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; 
 struct inet_bind_hashbucket *head; 
 struct hlist_node *node; 
 struct inet_bind_bucket *tb; 
 int ret; 
 struct net *net = sock_net(sk); 
 
 local_bh_disable(); 
 if (!snum) { 
///端口为0,也就是需要内核来分配端口. 
 int remaining, rover, low, high; 
///得到端口范围. 
 inet_get_local_port_range(&low, &high); 
 remaining = (high - low) + 1; 
 rover = net_random() % remaining + low; 
 
///循环来得到一个当前没有使用的端口. 
 do { 
///通过端口为key,来得到相应的inet_bind_bucket 
  head = &hashinfo->bhash[inet_bhashfn(net, rover, 
   hashinfo->bhash_size)]; 
  spin_lock(&head->lock); 
  inet_bind_bucket_for_each(tb, node, &head->chain) 
  if (tb->ib_net == net && tb->port == rover) 
///说明这个端口已被使用,因此需要将端口加1,重新查找. 
   goto next; 
  break; 
 next: 
  spin_unlock(&head->lock); 
///如果端口大于最大值,则将它赋值为最小值(这是因为我们这个端口是随机值,因此有可能很多端口就被跳过了),重新查找. 
  if (++rover > high) 
  rover = low; 
 } while (--remaining > 0); 
 
 /* Exhausted local port range during search? It is not 
  * possible for us to be holding one of the bind hash 
  * locks if this test triggers, because if 'remaining' 
  * drops to zero, we broke out of the do/while loop at 
  * the top level, not from the 'break;' statement. 
  */ 
 ret = 1; 
 if (remaining <= 0) 
  goto fail; 
///将要分配的端口号. 
 snum = rover; 
 } else { 
///指定端口号的情况.和上面的方法差不多,只不过只需要一次. 
 head = &hashinfo->bhash[inet_bhashfn(net, snum, 
  hashinfo->bhash_size)]; 
 spin_lock(&head->lock); 
 inet_bind_bucket_for_each(tb, node, &head->chain) 
  if (tb->ib_net == net && tb->port == snum) 
  goto tb_found; 
 } 
 tb = NULL; 
 goto tb_not_found; 
tb_found: 
///用来处理端口号已经被使用的情况.他被使用的socket不为空的情况. 
 if (!hlist_empty(&tb->owners)) { 
///fastreuse大于0说明其他的socket允许另外的socket也使用这个端口,而reuse表示当前的端口也允许和其他的端口分享这个port.并且socket的状态必须是TCP_LISTEN,才能做这个判断. 
 if (tb->fastreuse > 0 && 
   sk->sk_reuse && sk->sk_state != TCP_LISTEN) { 
  goto success; 
 } else { 
  ret = 1; 
///如果出错,调用inet_csk_bind_conflict.主要是有可能一些使用这个端口的socket,有可能使用不同的ip地址.此时,我们是可以使用这个端口的. 
  if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) 
  goto fail_unlock; 
 } 
 } 
tb_not_found: 
 ret = 1; 
///重新分配一个inet_bind_bucket,并链接到bhash. 
 if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep, 
   net, head, snum)) == NULL) 
 goto fail_unlock; 
 if (hlist_empty(&tb->owners)) { 
///设置当前端口的fastreuse,这个域也只能是处于listen的socket才能设置. 
 if (sk->sk_reuse && sk->sk_state != TCP_LISTEN) 
  tb->fastreuse = 1; 
 else 
  tb->fastreuse = 0; 
 } else if (tb->fastreuse && 
   (!sk->sk_reuse || sk->sk_state == TCP_LISTEN)) 
 tb->fastreuse = 0; 
success: 
///将这个socket加到这个端口的ower中. 
 if (!inet_csk(sk)->icsk_bind_hash) 
 inet_bind_hash(sk, tb, snum); 
 WARN_ON(inet_csk(sk)->icsk_bind_hash != tb); 
 ret = 0; 
 
fail_unlock: 
 spin_unlock(&head->lock); 
fail: 
 local_bh_enable(); 
 return ret; 
}

上一页  1 2 3 4 5 6 7 8 9  下一页

Tags:tcp connection setup

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接