📄 2_4网络代码阅读笔记(2) - china linux forum.htm
字号:
<BR>spin_lock(&head->lock); <BR>for (tb = head->chain; tb;
tb = tb->next) <BR>if (tb->port == rover) <BR>goto next;
<BR>break; <BR>next: <BR>spin_unlock(&head->lock); <BR>}
while (--remaining > 0); <BR>>>>>下面几步判断究竟找到相应的端口没有.
<BR>tcp_port_rover = rover;
<BR>spin_unlock(&tcp_portalloc_lock); <BR>/* Exhausted local
port range during search? */ <BR>ret = 1;
<BR>>>>>没有找到可用的端口 <BR>if (remaining <= 0) <BR>goto
fail; <BR>/* OK, here is the one we will use. HEAD is <BR>* non-NULL
and we hold it's mutex. <BR>*/ <BR>>>>>终于找到了一个可用的.
<BR>snum = rover;
<BR>>>>>找到了合适的没有使用的端口,tc=NULL,下面就免去了对端口重用的检查了 <BR>tb =
NULL; <BR>} else {
<BR>>>>>用户给出了端口,这里判断是否在tcp_bhash中已经有同样的端口
<BR>>>>>如果有则tb指向包含这个端口的桶,没有则tb=NULL <BR>head =
&tcp_bhash[tcp_bhashfn(snum)];
<BR>spin_lock(&head->lock); <BR>for (tb = head->chain; tb
!= NULL; tb = tb->next) <BR>if (tb->port == snum) <BR>break;
<BR>} <BR>>>>>如果端口已经存在在tcp_bhash之中,则要对是否允许重用进行检查 <BR>if
(tb != NULL && tb->owners != NULL) {
<BR>>>>>设置了fastreuse和reuse,且套接字状态不是倾听,则可以重用 <BR>if
(tb->fastreuse != 0 && sk->reuse != 0 &&
sk->state != TCP_LISTEN) { <BR>goto success; <BR>} else {
<BR>>>>>对端口是否能够重用进行检查,代码放到下面分析
<BR>............................ <BR>} <BR>} <BR>ret = 1;
<BR>>>>>在没有任何端口重用的情况下.创建一个桶,并且连入到tcp_bhash的正确位置 <BR>if
(tb == NULL && <BR>(tb = tcp_bucket_create(head, snum)) ==
NULL) <BR>goto fail_unlock; <BR>>>>>如果这是第一个绑定这个端口的sock
<BR>if (tb->owners == NULL) {
<BR>>>>>如果这个端口设为reuse,而且不在倾听状态,则设置bind桶的fastreuse
<BR>>>>>这样后续的想绑定这个端口的sock将不用多作判断就可以直接重用了 <BR>if
(sk->reuse && sk->state != TCP_LISTEN)
<BR>tb->fastreuse = 1; <BR>else <BR>tb->fastreuse = 0; <BR>}
else <BR>>>>>多个sock绑定这个端口 <BR>if (tb->fastreuse
&&
<BR>>>>>这个bind桶其它的sock都允许fastreust,如果这个sock不允许reuse
<BR>>>>>或者在倾听状态,则将fastreuse置为0,
<BR>>>>>则后面的想重用这个端口的就要进行上述的重重检查 <BR>((sk->reuse == 0)
|| (sk->state == TCP_LISTEN))) <BR>tb->fastreuse = 0;
<BR>success: <BR>>>>>将端口号保存到sk->num中 <BR>sk->num =
snum; <BR>>>>>将重用同一个端口的sock用双向链表连接起来,我们这个sock放最前面.
<BR>if (sk->prev == NULL) { <BR>if ((sk->bind_next =
tb->owners) != NULL) <BR>tb->owners->bind_pprev =
&sk->bind_next; <BR>tb->owners = sk;
<BR>>>>>前向指针指向bind桶的owners域 <BR>sk->bind_pprev =
&tb->owners;
<BR>>>>>sock的prev指针指向了这个bind桶.当要这个sock要释放这个端口的时候
<BR>>>>>就可以直接根据这个指针找到相应的struct tcp_bind_bucket结构
<BR>sk->prev = (struct sock *) tb; <BR>} else {
<BR>BUG_TRAP(sk->prev == (struct sock *) tb); <BR>} <BR>ret = 0;
<BR>fail_unlock: <BR>spin_unlock(&head->lock); <BR>fail:
<BR>local_bh_enable(); <BR>return ret; <BR>}
<BR><BR>下面是对本地端口重用的规则:(摘自tcp.h注释):
<BR>1:绑定到不同网络接口的套接字可以共享一个本地端口,如果不是这样,goto 2:
<BR>2:如果所有的套接字设置了reuse位,并且不处于TCP_LISTEN状态,则端口可以重用,如果 <BR>不是是这样,则goto
3: <BR>3:如果所有的套接字绑定到一个特定的本地地址,并且它们都不相同,则端口可以被重用
<BR><BR>对第二步,比较有意识,FTP服务器几乎天天在做这件事,为了对这种情况进行优化,特别在
<BR><BR>bind桶的定义(struct tcp_bind_bucket)中设置了一个标志位. <BR>当我们增加一个struct
sock到一个bind桶的链表中时,进行如下的检查 <BR>(newsk->reuse &&
(newsk->state != TCP_LISTEN)) <BR>只要所有的加入这个bind桶的struct
sock满足这个检查,这个标志将置位.
<BR>tcp_v[46]_verify_bind检查这个标志,如果设置了这个标志,并且struct sock的reuse标
<BR>志了设置了的话,就不 <BR>需要遍历这个bind桶上的struct sock链表,仅仅返回成功.
<BR>听起来好像作了很多工作,但必须这样作.在一些早期的实现中(例如FreeBSD),必须遍历 <BR>每个被FTP服务器打开的
<BR>数据端口链表.(这里几句翻不动了,自己看原文吧) <BR>* Needless to say, this does not
scale at all. With a couple <BR>* thousand FTP users logged onto
your box, isn't it nice to know that new <BR>* data ports are
created in O(1) time? I thought so. ;-) -DaveM
<BR>好了看完了注释,可以看看上面的代码了.让我们先看看它的定义bind桶的定义. <BR>struct
tcp_bind_bucket { <BR>unsigned short port; <BR>unsigned short
fastreuse; <BR>struct tcp_bind_bucket *next; <BR>struct sock
*owners; <BR>struct tcp_bind_bucket **pprev; <BR>};
<BR>这里猜想上面说的标志为fastreuse,上面结构中owners怀疑就是复用到这个端口的所有 <BR>的struct
sock的链表. <BR>它们用struct sock结构的bind_next连接.
<BR><BR>>>>>>>>>>>>>>>>>>>>>>>>>对端口重用进行检查的代码<<<<<<<<<<<<<<<<<<<<<<<<
<BR><BR>>>>>得到链头 <BR>struct sock *sk2 = tb->owners;
<BR>int sk_reuse = sk->reuse; <BR>>>>>一次遍历一个struct
sock,这个sock绑定了这个端口 <BR>for( ; sk2 != NULL; sk2 = sk2->bind_next)
{ <BR>>>>>如果满足了下面三个条件,端口重用就失败:
<BR>>>>>1.如果绑定的网络接口相同而且
<BR>>>>>2.这两个sock其中之一或者全部不允许重用(reuser=0),或者是已经绑定的sock正在
<BR>>>>> 倾听状态 <BR>>>>>3.这两个sock的接受地址均相同
<BR>>>>>其它情况就允许重用了.呵呵,看来重用不是太难 <BR>if (sk != sk2
&& <BR>sk->bound_dev_if == sk2->bound_dev_if) { <BR>if
(!sk_reuse || <BR>!sk2->reuse || <BR>sk2->state == TCP_LISTEN)
{ <BR>if (!sk2->rcv_saddr || <BR>!sk->rcv_saddr ||
<BR>(sk2->rcv_saddr == sk->rcv_saddr)) <BR>break; <BR>} <BR>}
<BR><BR>欢迎访问"Unix编程" <BR>telnet apue.dhs.org 2323 <BR>or
http://apue.dhs.org
<P class=small>文章选项: <A
href="http://www.linuxforum.net/forum/printthread.php?Cat=&Board=linuxK&main=147050&type=post"
target=_blank><IMG align=absMiddle alt=打印 border=0
src="2_4网络代码阅读笔记(2) - China Linux Forum.files/print.gif"></A>
</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE align=center border=0 cellPadding=4 cellSpacing=0 width="95%">
<TBODY>
<TR>
<TD align=left class=small> </TD>
<TD align=right class=small><A
href="http://www.linuxforum.net/forum/printthread.php?Cat=&Board=linuxK&main=147050&type=thread"
target=_blank><IMG align=top border=0
src="2_4网络代码阅读笔记(2) - China Linux Forum.files/printthread.gif"> 打印</A>
</TD></TR></TBODY></TABLE><BR>
<TABLE align=center border=0 cellPadding=0 cellSpacing=0 width="95%">
<TBODY>
<TR>
<TD class=tableborders>
<TABLE border=0 cellPadding=3 cellSpacing=1 width="100%">
<TBODY>
<TR class=darktable>
<TD align=right>
<TABLE border=0>
<TBODY>
<TR>
<TD class=navigation noWrap><IMG align=absMiddle alt=*
src="2_4网络代码阅读笔记(2) - China Linux Forum.files/greyflat.gif">平坦模式
</TD>
<TD class=navigation noWrap><A
href="http://www.linuxforum.net/forum/showthreaded.php?Cat=&Board=linuxK&Number=147050&page=120&view=collapsed&sb=5&o=all&vc=1"><IMG
align=absMiddle alt=树状模式,一封一封读 border=0
src="2_4网络代码阅读笔记(2) - China Linux Forum.files/threaded.gif">树状模式</A>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE align=center border=0 cellPadding=0 cellSpacing=0 width="95%">
<TBODY>
<TR>
<TD align=right>
<FORM action=http://www.linuxforum.net/forum/jumper.php method=post><INPUT
name=Cat type=hidden> <SPAN class=onbody>前往讨论区 </SPAN><SELECT
class=formboxes name=board> <OPTION value=-CATJUMP-1>*Linux 社区和文化*
-----<OPTION value=new> 社区公告栏<OPTION
value=uglyduck> 社区服务台<OPTION
value=linuxnews> 业界新闻与评论<OPTION
value=linuxtalk> 自由软件杂谈<OPTION
value=software> Linux软件快递<OPTION
value=Tworkshop> 中文MAN-PAGE计划(CMPP)<OPTION
value=tcl> Linux图书与评论<OPTION
value=job> 招聘和求职<OPTION value=-CATJUMP-2>*Linux
桌面与办公自动化* -----<OPTION value=chinese> Linux
中文环境和中文化<OPTION value=office> Linux桌面与办公软件<OPTION
value=game> Linux 多媒体与娱乐版<OPTION
value=mozilla> 自由之窗Mozilla<OPTION
value=laptop> 笔记本电脑上的Linux<OPTION
value=-CATJUMP-3>*Linux 入门及网络应用* -----<OPTION
value=debian> Debian 一族<OPTION
value=nm> 网络管理技术<OPTION
value=newbie> Linux 安装与入门<OPTION
value=web> WEB服务器和FTP服务器<OPTION
value=dns> 域名服务器和邮件服务器<OPTION
value=proxy> Linux防火墙和代理服务器应用<OPTION
value=samba> 文件及打印服务器<OPTION
value=training> 技术培训与认证<OPTION value=-CATJUMP-4>*Linux
高级应用* -----<OPTION selected
value=linuxK> Linux内核技术<OPTION
value=embedded> 嵌入开发推进计划 (OpenARM)<OPTION
value=driver> Linux设备驱动程序<OPTION
value=cluster> Linux 集群技术<OPTION
value=db> LINUX平台数据库<OPTION
value=cpu> CPU 与 编译器<OPTION
value=security> 系统和网络安全<OPTION value=-CATJUMP-5>*Linux
环境下的程序设计* -----<OPTION
value=kylix> LINUX下的快速开发工具(RAD)<OPTION
value=program> C/C++编程版<OPTION
value=php3> PHP 技 术<OPTION
value=java> Java&jsp技术<OPTION
value=vrml> Shell编程技术<OPTION
value=perl> Perl 编 程<OPTION
value=python> Python 编 程<OPTION
value=xml> XML/Web Service 技术<OPTION
value=-CATJUMP-6>*永远的 UNIX* -----<OPTION
value=unix> 永远的Unix<OPTION
value=bsd> FreeBSD世界<OPTION value=-CATJUMP-7>*IT 人生*
-----<OPTION value=life> IT 人生</OPTION></SELECT> <INPUT class=buttons name=Jump type=submit value=出发>
</FORM></TD></TR></TBODY></TABLE>
<P>
<TABLE align=center border=0 cellPadding=0 cellSpacing=0 width="95%">
<TBODY>
<TR>
<TD class=tableborders>
<TABLE border=0 cellPadding=3 cellSpacing=1 width="100%">
<TBODY>
<TR class=darktable>
<TD>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD align=left><A href="mailto:davidd@linuxforum.net">Contact
Us</A> </TD>
<TD align=right><A
href="http://www.linuxforum.net/">LINUXFORUM.NET</A>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -