smsong_cu 发表于 2011-12-21 08:43

Linux网络代码导读v0.2

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">原文地址:</span><span class="Apple-style-span" style="line-height: 18px; "><a href="http://blogold.chinaunix.net/u/2108/showart_6076.html" target="_blank">http://blogold.chinaunix.net/u/2108/showart_6076.html</a></span></p><p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">1 </span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">前言</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">许多人在分析</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">linux</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">代码时对网络部分(主要是</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">src/linux/net</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">src/linux/include/net</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">及</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">src/linux/include/linux</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">目录下的文件)比较感兴趣,确实,尽管已经从书本上学到了大量的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">TCP/IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">原理,不读源码的话,头脑中还是建立不起具体的印象。而分析这部分代码的一个问题便是代码众多而资料很少。这篇文章的目的就是勾勒出一个框架,让读者能够大致能够了解</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">TCP/IP</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">究竟是怎么工作的。以前见到的许多代码分析都是基于</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">2.0</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">内核的,在新的内核中许多函数变了名字,这尤其给初学者带来了困难,本文是以</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">2.4.0-test9</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的代码作例子,这样对照代码时可能更清晰些。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">其实网络部分的代码我只对防火墙部分一行行仔细分析过,其他许多地方也只是一知半解,如果理解有误,欢迎指正。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">建议在看本文的同时,用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">source insight(<a href="http://www.soucedyn.com/" target="_blank" target="_blank"><span style="color:#336699">www.soucedyn.com</span></a>)</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">建立一个项目,同时看代码,这样可能效果更好点。我也用过其他的一些工具,但在分析大量的代码的时候,没有一个工具比它更方便的了。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
2 </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">正文</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">ISO</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">的七层模型都非常熟悉了,当然,对于</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">internet,</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">用四层模型更为适合。在这两份模型里,网络协议以层次的形式出现。而</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">LINUX</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的内核代码中,严格分出清楚的层次却比较困难,因为除了一些</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">"</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">内核线程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">(kernel
thread</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">外</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">)"</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,整个内核其实是个单一的进程。因此所谓</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">"</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">网络层</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">",</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">只是一组相关的函数,而各层之间大多通过一般的函数调用的方式完成交互。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">而从逻辑上,网络部分的代码更应该这样分层更为合理:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
.BSD socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">层:这一部分处理</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">BSD
socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">相关操作,每个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">在内核中以</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">struct socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">结构体现。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">这一部分的文件主要有:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/net/socket.c /net/protocols.c
etc</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">.INET socket</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">层:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">BSD socket</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">是个可以用于各种网络协议的接口,而当用于</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">tcp/ip</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,即建立了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">AF_INET</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">形式的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">时,还需要保留些额外的参数,于是就有了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">struct
sock</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">结构。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">文件主要有:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/net/ipv4/protocol.c
/net/ipv4/af_inet.c /net/core/sock.c etc</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">.TCP/UDP</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">层:处理传输层的操作,传输层用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct inet_protocol</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">和</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct proto</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">两个结构表示。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">文件主要有:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/net/ipv4/udp.c
/net/ipv4/datagram.c /net/ipv4/tcp.c /net/ipv4/tcp_input.c<br>
/net/ipv4//tcp_output.c /net/ipv4/tcp_minisocks.c /net/ipv4/tcp_output.c<span class="apple-converted-space">&nbsp;</span><br>
/net/ipv4/tcp_timer.c etc</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">.IP</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">层:处理网络层的操作,网络层用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct packet_type</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">结构表示。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">文件主要有:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/net/ipv4/ip_forward.c
ip_fragment.c ip_input.c ip_output.c etc.</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">.</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">数据链路层和驱动程序:每个网络设备以</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct net_device</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">表示,通用的处理在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">dev.c</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中,</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">驱动程序都在</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/driver/net</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">目录下。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">网络部分还有很多其他文件,如防火墙,路由等,一般根据看到名字便能猜测出相应的处理,此处不再赘述。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">现在我要给出一张表,全文的内容就是为了说明这张表(如果你觉得我在文章中的语言比较乏味,尽可抛掉他们,结合这张表自己看代码)。在我最初看网络部分代码时,比较喜欢《</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">linux kernel internals</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">》的第八章的一段,其中有一个进程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">A</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">通过网络远程向另一进程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">B</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">发包的例子,详细介绍了一个数据包如何从网络堆栈中走过的过程。我觉得这样可以更迅速的帮助读者看清森林的全貌,因此本文参照这种结构来</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">叙述。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">^<br>
| sys_read fs/read_write.c<br>
| sock_read net/socket.c<br>
| sock_recvmsg net/socket.c<br>
| inet_recvmsg net/ipv4/af_inet.c<br>
| udp_recvmsg net/ipv4/udp.c<br>
| skb_recv_datagram net/core/datagram.c<br>
| -------------------------------------------<br>
| sock_queue_rcv_skb include/net/sock.h<br>
| udp_queue_rcv_skb net/ipv4/udp.c<br>
| udp_rcv net/ipv4/udp.c<br>
| ip_local_deliver_finish net/ipv4/ip_input.c<br>
| ip_local_deliver net/ipv4/ip_input.c<br>
| ip_recv net/ipv4/ip_input.c<br>
| net_rx_action net/dev.c<br>
| -------------------------------------------<br>
| netif_rx net/dev.c<br>
| el3_rx driver/net/3c309.c<br>
| el3_interrupt driver/net/3c309.c</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">==========================</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">| sys_write fs/read_write.c<br>
| sock_writev net/socket.c<span class="apple-converted-space">&nbsp;</span><br>
| sock_sendmsg net/socket.c<br>
| inet_sendmsg net/ipv4/af_inet.c<br>
| udp_sendmsg net/ipv4/udp.c<br>
| ip_build_xmit net/ipv4/ip_output.c<br>
| output_maybe_reroute net/ipv4/ip_output.c<br>
| ip_output net/ipv4/ip_output.c<br>
| ip_finish_output net/ipv4/ip_output.c<br>
| dev_queue_xmit net/dev.c<br>
| --------------------------------------------<br>
| el3_start_xmit driver/net/3c309.c<br>
V</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">我们假设的环境如下:有两台主机通过互联网联在一起,其中一台机子运行这一个进程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">A</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">,另外一台运行进程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">B</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,进程</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">A</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">将向进程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">B</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">发出一条信息,比如</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">"Hello",</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">而</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">B</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">接受此信息。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
TCP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">处理本身非常复杂,为了便于叙述,在后面我们将用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">UDP</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">作为例子。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"=""><br>
2.1 </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">建立套接字</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在数据发送之前,要建立一个套接字(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">)</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">在两边的程序中都会调用如下语句:</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">...<br>
int sockfd;<br>
sockfd=socket(AF_INET,SOCK_DGRAM,0);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">这是个系统调用,因此会通过</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">0x80</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中断进入系统内核,调用内核中的相应函数</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">.</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">当寻找系统调用在内核中的对应流程时,一般前面加入</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">"sys_"</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">再找就是了,如对</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">fork</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">来说,就是调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sys_fork</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">。但是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">相关调用有些特殊,所有的这类调用都是通过一个入口,即</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">sys_socketcall</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">进入系统内核,然后再通过参数调用具体的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">sys_socket,socket_bind</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">等函数。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">sys_socket</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">会调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sock_create</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">产生一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">struct
socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">结构(见</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">include/linux/net.h</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">),每个套接字在内核中都有一个这样的结构对应,在初始化了此结构的一些通用成员后(如分配</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">inode</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,根据第二个参数为</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">type</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">项赋值等),会根据其一个参数作响应的调度,即这</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">一句:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
net_families-&gt;create(sock, protocol);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">我们的程序的第一个参数是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">AF_INET</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,所以此函数指针会指向</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">inet_create</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">();(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">net_families</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">是个数组,保留了网络协议族(</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">net families</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">)的信息,而这些协议族用</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock_register</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">加载。)</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">struct
socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">结构结构中最重要的信息保留在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct sock</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">结构中,这个结构在网络代码中经常使用,建议把它和其他常见结构(如</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">)打印出来放在手边。在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">inet_create</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">会为此结构分配内存,并根据套接字类型(其实就是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数的第二个参数),作各自不同的初始化:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
if (sk-&gt;prot-&gt;init)<span class="apple-converted-space">&nbsp;</span><br>
sk-&gt;prot-&gt;init(sk);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">如果类型是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">SOCK_STREAM</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的话会调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">tcp_v4_init_sock</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,而</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">SOCK_DGRAM</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">类型的</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">没有额外的初始化了,到此</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">调用结束。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">还有一个值得注意的地方是当</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">inet_create</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">()调用完后,会接着调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sock_map_fd</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数,这个函数中会为套接字分配一个文件描述符并分配一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">file</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">文件。在应用层便可象处理文件一样处理套接字了。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">开始的时候可能有些流程难以跟下去,主要便是这些函数指针的实际指向会根据类型变化。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"=""><br>
2.2 </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">发送数据</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">当进程</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">A</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">想发送数据时,程序中会调用如下语句</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">(</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">如果用</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sendto</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">函数的话会走类似的流程,略</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">)</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
write(sockfd,"Hello",strlen("Hello"));<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">write</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">在内核中对应的函数就是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sys_write</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,此函数首先根据文件描述符找到</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct file</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">结构,如果此文件存在(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">file</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">指针非空)且可写(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">file-&gt;f_mode &amp; FMODE_WRITE</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">为</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">true</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">),便调用此文件结构的写操作:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
if (file-&gt;f_op &amp;&amp; (write = file-&gt;f_op-&gt;write) != NULL)<br>
ret = write(file, buf, count, &amp;file-&gt;f_pos);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">其中</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">f_op</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">是个</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">struct file_operations</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">结构指针,在</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock_map_fd</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中将其指向</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">socket_file_ops</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,其定义如下(</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/net/socket.c</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">):</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
static struct file_operations socket_file_ops = {<br>
llseek: sock_lseek,<br>
read: sock_read,<br>
write: sock_write,<br>
poll: sock_poll,<br>
ioctl: sock_ioctl,<br>
mmap: sock_mmap,<br>
open: sock_no_open, /* special open code to disallow open via /proc */<br>
release: sock_close,<br>
fasync: sock_fasync,<br>
readv: sock_readv,<br>
writev: sock_writev<br>
};</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">此时</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">wirte</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">函数指针显然指向了</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock_write</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,我们跟下去看</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">,</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">此函数将一个字符串缓冲整理成</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct msghdr</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,最后调用了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sock_sendmsg.</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">sock_sendmsg</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">中的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">scm_send</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">我不了解(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">scm</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">Socket
level control messages</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的简写),好在它也不是很关键,我们注意到这句:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
sock-&gt;ops-&gt;sendmsg(sock, msg, size, &amp;scm);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">又是个函数指针,</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sock-&gt;ops</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">inet_create</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">()函数中被初始化,由于我们我们是</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">UDP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">的套接字,</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock-&gt;ops</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">指向了</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">inet_dgram_ops</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">(即</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock-&gt;ops =
&amp;inet_dgram_ops;</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">),其定义在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">net/ipv4/Af_inet.c</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
struct proto_ops inet_dgram_ops = {<br>
family: PF_INET,</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">release: inet_release,<br>
bind: inet_bind,<br>
connect: inet_dgram_connect,<br>
socketpair: sock_no_socketpair,<br>
accept: sock_no_accept,<br>
getname: inet_getname,<span class="apple-converted-space">&nbsp;</span><br>
poll: datagram_poll,<br>
ioctl: inet_ioctl,<br>
listen: sock_no_listen,<br>
shutdown: inet_shutdown,<br>
setsockopt: inet_setsockopt,<br>
getsockopt: inet_getsockopt,<br>
sendmsg: inet_sendmsg,<br>
recvmsg: inet_recvmsg,<br>
mmap: sock_no_mmap,<br>
};</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">因此我们要看得便是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">inet_sendmsg</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">()函数了,而马上,这个函数又通过函数指针调用了另一函数:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
sk-&gt;prot-&gt;sendmsg(sk, msg, size);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">我们不得不再次寻找其具体指向。看到这里,说点题外话,怎么才能找到其具体定义呢?我一般是这样</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">:</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">对上例而言,</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">sk</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">是个</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">struct sock</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">结构,到其定义(</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">linux/net/sock.h</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中)出看到</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">prot</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">是个</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">struct proto</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">结构,此时我们便在源代码树中寻找所有此结构的实例(这些诸如跳到定义,寻找引用等工作在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">source insight</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中实在太方便快速了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">^_^</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">)</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">很快便会发现诸如</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">udp_prot</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">tcp_prot</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">raw_prot</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">等,猜测是用了</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">udp_prot,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">便再找一下它在源代码中的引用情况,果然发现在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">inet_create</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中有这么一句:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
prot=&amp;udp_prot;<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">其实如果前面看</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">inet_create</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数时仔细一点会早点发现了,但我总没有这么细心</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">:)</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">我们顺着</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">udp_sendmsg</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">往下走:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">在这个函数的主要作用是填充</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">UDP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">头(源端口,目的端口等),接着调用了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
ip_route_output</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">,作用是查找出去的路由,而后:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
ip_build_xmit(sk,<br>
(sk-&gt;no_check == UDP_CSUM_NOXMIT ?<br>
udp_getfrag_nosum :<br>
udp_getfrag),<br>
&amp;ufh, ulen, &amp;ipc, rt, msg-&gt;msg_flags);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">ip_build_xmit</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">函数的很大比例是生成</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sk_buff,</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">并为数据包加入</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">头。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">后面有这么一句:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
rt-&gt;u.dst.dev,output_maybe_reroute);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">简单的说,在没有防火墙代码干预的情况下,你可以将此处理解为直接调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">output_maybe_reroute</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">,(具体可参看绿盟月刊</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">14</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">期中的《内核防火墙</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">netfilter</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">入门</span><span style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""> </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">》)</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">而</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">output_maybe_reroute</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中只有一句:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
return skb-&gt;dst-&gt;output(skb);</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">依旧照上面的方法(不过这个确实不太好找),发现其实这个指针是在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_route_output</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中指定的,(提示:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_route_output_slow</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">中:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">rth-&gt;u.dst.output=ip_output;</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">)</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">,ip_route_output</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的作用便是查找路由,并将结果记录到</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">skb-&gt;dst</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">于是,我们开始看</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_output</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数了,而它马上又走向了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_finish_output</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">~~。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">每个网络设备,如网卡,在内核中由一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">net_device</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">表示,在</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_finish_output</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中找到其用到的设备(也是在</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">ip_route_output</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中初始化的),这个参数在会传给</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">netfilter</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">在</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">NF_IP_POST_ROUTING</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">点登记的函数,结束后调用</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_finish_output2</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,而这个函数中又会调用:</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
hh-&gt;hh_output(skb);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">闲话少叙,实际调用了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">dev_queue_xmit</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,到此我们完成了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">TCP/IP</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">层的工作,开始数据链路层的处理。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在做了一些判断之后,实际的调用是这句:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
dev-&gt;hard_start_xmit(skb, dev);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">这个函数是在网卡的驱动程序中定义的,每个不同的网卡有不同的处理,我的网卡是比较通用的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">3c509</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">(其驱动程序是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">3c509.c),</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在网卡处理化的时候(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">el3_probe</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">),有:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
dev-&gt;hard_start_xmit = &amp;el3_start_xmit;<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">再往下便是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">IO</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">操作,将数据包真正的发到网络上去,至此发送过程结束。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中间我说的有些草率,完全没顾的上中间的如出错,阻塞,分片等特殊处理,只是将理想的过程描述出来。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">这篇短文的目的也只是帮助大家建立个大致的印象,其实每个地方的都有非常复杂的处理(尤其是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">TCP</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">部分)。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"=""><br>
2.3 </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">接受数据</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">当有数据到达网卡的时候,会产生一个硬件中断,然后调用网卡驱动程序中的函数来处理,对我的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">3c509</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">网卡来说,其处理函数为:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">el3_interrupt</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">。(相应的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">IRQ</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">号是在系统启动,网卡初始化时通过</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">request_irq</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数决定的。)这个中断处理程序首先要做的当然就是进行一些</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">IO</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">操作将数据读入(读</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">IO</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">用</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">inw</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">函数),当数据帧成功接受后,执行</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">el3_rx(dev)</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">进一步处理。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">el3_rx</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中,收到的数据报会被封装成</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">struct sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,并脱离驱动程序,转到通用的处理函数</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">netif_rx</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">(</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">dev.c</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">)中。为了</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">CPU</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">的效率,上层的处理函数的将采用软中断的方式激活,</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">netif_rx</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">的一个重要工作就是将传入的</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">放到等候队列中,并置软中断标志位,然后便可放心返回,等待下一次网络数据包的到来:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
__skb_queue_tail(&amp;queue-&gt;input_pkt_queue,skb);<br>
__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">这个地方在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">2.2</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">内核中一直被称为</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">"</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">底半</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">"</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">处理</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">--bottom half,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">其内部实现基本类似,目的是快速的从中断中返回。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">过了一段时间后,一次</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">CPU</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">调度会由于某些原因会发生(如某进程的时间片用完)。在进程调度函数即</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">schedule()</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中,会检查有没有软中断发生,若有则运行相应的处理函数</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">:<br>
...<br>
if (softirq_active(this_cpu) &amp; softirq_mask(this_cpu))<br>
goto handle_softirq;<br>
handle_softirq_back:<br>
...<br>
...<br>
handle_softirq:<br>
do_softirq();<br>
goto handle_softirq_back;<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在系统初始化的时候,具体说是在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">net_dev_init</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">中,此软中断的处理函数被定为</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">net_rx_action</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">当下一次进程调度被执行的时候,系统会检查是否发生</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">NET_TX_SOFTIRQ</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">软中断,若有则调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">net_rx_action</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">net_tx_action</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">函数既是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">2.2</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">版本中的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">net_bh</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">函数</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">,</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">在内核中有两个全局变量用来登记网络层的,一个是链表</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ptype_all</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,另外一个是数组</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ptype_base</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,他们记载了所有内核能够处理的第三层(按照</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">OSI7</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">层模型)协议。每个网络层的接收处理由一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
struct packet_type</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">表示,而这个结构将通</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">dev_add_pack</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数将他们登记到</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ptype_all</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">或</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">ptype_base</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中。只有</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">packet_type</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中的</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">type</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">项为</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ETH_P_ALL</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">时,才会登记到</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ptype_all</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">链表中,否则如</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_packet_type</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">,会在数组</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ptype_base</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">找到相应的位置。两者不同点是如果是以</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">ETH_P_ALL</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">类型登记</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">,</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">那么处理函数会受到所有类型的包,否则只能处理自己登记的类型的。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">skb-&gt;protocol</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">是在</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">el3_rx</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中赋值的,其实就是以太帧头信息中提取出的上层协议名,对于我们的例子来说,这个值是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ETH_P_IP</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,所以在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">net_tx_action</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中,会选择</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">层的接收处理函数,而从</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_packet_type </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">不难看出,这个函数便是</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_recv</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">()。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
pt_prev-&gt;func</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">(实际指向</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_recv</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">)前面有一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">atomic_inc(&amp;skb-&gt;users)</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">操作(在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">2.2</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">内核中这个地方是一句</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">skb_clone</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,原理类似),目的是增加这个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的引用数。网络层的接收函数在处理完或因为某些原因要丢弃此</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">时(如防火墙)会调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">kfree_skb</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,而</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">kfree_skb</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中首先会检查是否还有其他地方需要此函数,如果没有地方再用,才真正释放此内存(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">__kfree_skb</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">),否则只是计数器减一。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">现在我们便来看看</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_recv</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">net/ipv4/ip_input.c</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">)。这个函数的操作是非常清晰的</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">:</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">首先检查这个包的合法性(版本号,长度,校验和等是否正确),如果合法则进行接下来的处理。在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">2.4</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">内核中,为了灵活处理防火墙代码,将原来的一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_recv</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">分成了两部分,即将将原来的的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_recv</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的后半段独立出一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_rcv_finish</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数。在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">ip_rcv_finish</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中,一部分是带有</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">选项(如源路由等)的</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">包,例外就是通过</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_route_input</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">查找路由,并将结果记录到</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">skb-&gt;dst</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中。此时接收到的包有两种,发往本地进程(需要传往上层协议)或转发(用作网关时),此时需要的处理函数也不相同,如果传往本地,则调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_local_deliver(/net/ipv4/ip_input.c),</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">否则调用</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_forward(/net/ipv4/ip_forward.c).skb-&gt;dst-&gt;input</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">这个函数指针会将数据报领上正确的道路。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">对我们的例子而言,此时应该是调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_local_deliver</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的时候了。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">发来的包很有可能是碎片包,这样的话则首先应该把它们组装好再传给上层协议,这当然也是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">ip_local_deliver</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数所做的第一份工作,如果组装成功(返回的</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">不为空),则继续处理(详细的组装算法可参见绿盟月刊</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">13</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">期中的《</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">分片重组的分析和常见碎片攻击》)。</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">但此时代码又被</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">netfilter</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">一分为二了,象前面一样,我们直接到后半段,即</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">ip_local_deliver_finish(/net/ipv4/ip_input.c)</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中去。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">传输层(如</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">TCP,UDP</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">RAW</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">)的处理被登记到了</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">inet_protos</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">中(通过</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">inet_add_protocol</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">)。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ip_local_deliver_finish</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">会根据</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">IP</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">头信息中的上层协议信息(即</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"="">iph-&gt;protocol</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">),调用相应的处理函数。为了简便,我们采用了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">udp,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">此时的</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">ipprot-&gt;handler</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">实际便是</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">udp_rcv</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">了。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">前面已经提到,在应用程序中建立的每个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">在内核中有一个</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">struct socket/struct sock</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">对应。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">udp_rcv</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">会通过</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">udp_v4_lookup</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">首先找到在内核中的</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">然后将其作参数调用</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">udp_queue_rcv_skb</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">(</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">/net/ipv4/udp.c</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">)。马上,</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock_queue_rcv_skb</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">函数被调用,此函数将</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">放入等待队列,然后通知上层数据到达:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
kb_set_owner_r(skb, sk);<br>
skb_queue_tail(&amp;sk-&gt;receive_queue, skb);<br>
if (!sk-&gt;dead)<br>
sk-&gt;data_ready(sk,skb-&gt;len);<br>
return 0;<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">sk-&gt;data_ready</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">的定义在</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">结构初始化的时候(</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sock_init_data</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">):</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
...<br>
sk-&gt;data_ready=sock_def_readable;<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">现在我们便要从上往下看起了:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">进程</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">B</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">要接收数据报,在程序里调用:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""><br>
...<br>
read(sockfd,buff,sizeof(buff));<br>
...</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">此系统调用在内核中的函数是</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sys_read(fs/read_write.c)</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">以下的处理类似</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">write</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的操作,不再详述</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">.udp_recvmsg</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">函数会调用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">skb_recv_datagram</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">,如果数据还没有到达,且</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">socket</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">设为阻塞模式时,进程会挂起(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">signal_pending(current)</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">),直到</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">data_ready</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">通知进程资源得到满足后继续处理(</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">wake_up_interruptible(sk-&gt;sleep);</span><span style="font-size:
10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">)。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">2.4 skbuff</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">网络代码中有大量的处理涉及对</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的操作,尽管此文中尽量将其回避了,但在仔细分析的时候则必须对此作分析,数据包在网络协议层是以</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的形式传送处理的,可以说它是网络部分最重要的数据结构。具体分析建议参看</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">alan cox</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的《</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">Network
Buffers And Memory Management</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">》,这篇发表在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">1996</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">年</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">10</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">月的</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">linux journal</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">上。</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">这里引用</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">phrack
55-12</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">期中的一幅图</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">,</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">尽管它只描绘了</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"="">sk_buff</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">的极小的一个侧面,但却非常有用,尤其是当你像我一样总忘记了</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">skb_put</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">是向前还是向后调指针的时候:)</span><span lang="EN-US" style="font-size:
10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">--- -----------------hand<br>
^ | |<br>
| | | ^ skb_push<br>
| | | |<br>
| -----------------data--- ---<span class="apple-converted-space">&nbsp;</span><br>
| | | ^ |<br>
true | | | v skb_pull<br>
size | | len<br>
| | | | ^ skb_trim<span class="apple-converted-space">&nbsp;</span><br>
| | | v |<br>
| -----------------tail--- ---<br>
| | | |<span class="apple-converted-space">&nbsp;</span><br>
| | | v skb_put<br>
v | |<br>
--- -----------------end</span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">linux</span><span style="font-size:10.5pt;
mso-ascii-font-family:Verdana;mso-hansi-font-family:Verdana;color:black">网络层效率:在</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">linux</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">的网络层代码中指针被大量应用,其目的就是避免数据拷贝这类耗费系统资源的操作。一个数据包的数据段部分在读入或发出时只经过两次拷贝,即从网卡中考到核心态内存,和从核心态内存考到用户态内存。前些天看到,在一些提高</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">sniffer</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">抓包效率的尝试中,</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">turbo packet(</span><span style="font-size:10.5pt;mso-ascii-font-family:
Verdana;mso-hansi-font-family:Verdana;color:black">一个内核补丁</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">)</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">采用了核心态和</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">用户态共享一段内存的办法,又减少了一次数据拷贝,进一步提高了效率。</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"=""><br>
3 </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">后记:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">这次的投稿又是到了最后关头仓促写出来的,看着里面拙劣的文笔,实在觉得有点对不住观众~~如果有时间我会把这部分好好重写的,其实这也是我一直的愿望:)</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"=""><br>
4 </span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">参考文献:</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"=""></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"=""> phrack 55-12</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">期</span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
2nd Edition<br>
Network Buffers And Memory Management Alan Cox<br>
<a href="http://www2.linuxjournal.com/lj-issues/issue30/1312.html" target="_blank" target="_blank"><span style="color:#336699">http://www2.linuxjournal.com/lj-issues/issue30/1312.html</span></a><br>
</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;
mso-hansi-font-family:Verdana;color:black">浙大源码分析报告《</span><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";color:black"="">Linux</span><span style="font-size:10.5pt;mso-ascii-font-family:Verdana;mso-hansi-font-family:
Verdana;color:black">网络设备分析》潘纲</span><span class="apple-converted-space"><span lang="EN-US" style="font-size:10.5pt;font-family:" verdana","sans-serif";="" color:black"="">&nbsp;</span></span><span lang="EN-US" style="font-size:10.5pt;
font-family:" verdana","sans-serif";color:black"=""><br>
Linux IP Networking--A Guide to the Implementation and Modification of
theLinux Poptocol Stack<br>
Glenn Herrin May 31,2000<span class="apple-converted-space">&nbsp;</span><a href="http://www.movement.uklinux.net/linux-net.pdf" target="_blank" target="_blank"><span style="color:#336699">http://www.movement.uklinux.net/linux-net.pdf</span></a></span></p>

<p style="margin-top:12.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:
0cm;line-height:15.75pt"><span lang="EN-US" style="font-size:10.5pt;font-family:
" verdana","sans-serif";color:black"="">http://www.nsfocus.net/index.php?act=sec_self&amp;do=view&amp;doc_id=507</span></p>
页: [1]
查看完整版本: Linux网络代码导读v0.2