﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-My C++-随笔分类-linux</title><link>http://www.cppblog.com/finehai/category/11208.html</link><description>当时只道是寻常~</description><language>zh-cn</language><lastBuildDate>Tue, 24 Apr 2012 19:05:58 GMT</lastBuildDate><pubDate>Tue, 24 Apr 2012 19:05:58 GMT</pubDate><ttl>60</ttl><item><title>linux内核网络栈</title><link>http://www.cppblog.com/finehai/archive/2012/04/24/172589.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Tue, 24 Apr 2012 05:50:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/24/172589.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/172589.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/24/172589.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/172589.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/172589.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt;"> </span><div><div> <div><strong style="font-size: 14pt;"><br /><div><span style="font-size: 14pt;"><br />一、linux内核网络栈代码的准备知识<br /><br /></span></div><br /></strong><strong style="font-size: 12pt;">1.</strong><span style="font-size: 12pt;"> </span><strong style="font-size: 12pt;">linux内核ipv4网络部分分层结构</strong><span style="font-size: 12pt;">：</span></div> <div>&nbsp;</div> <div><br /><strong style="font-size: 12pt;">BSD socket层： </strong>这一部分处理BSD socket相关操作，每个socket在内核中以struct socket结构体现。这一部分的文件</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">主要有：/net/socket.c /net/protocols.c etc</span><br /><br /><strong style="font-size: 12pt;">INET socket层：</strong>BSD socket是个可以用于各种网络协议的接口，而当用于tcp/ip，即建立了AF_INET形式的socket时，</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">还需要保留些额外的参数，于是就有了struct sock结构。文件主要</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">有：/net/ipv4/protocol.c /net/ipv4/af_inet.c /net/core/sock.c etc</span><br /><br /><strong style="font-size: 12pt;">TCP/UDP层：</strong>处理传输层的操作，传输层用struct inet_protocol和struct proto两个结构表示。文件主要</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">有：/net/ipv4/udp.c /net/ipv4/datagram.c /net/ipv4/tcp.c  /net/ipv4/tcp_input.c /net/ipv4//tcp_output.c /net/ipv4/tcp_minisocks.c  /net/ipv4/tcp_output.c&nbsp;/net/ipv4/tcp_timer.c </span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">etc&nbsp;&nbsp;</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><strong style="font-size: 12pt;">IP层：</strong>处理网络层的操作，网络层用struct packet_type结构表示。文件主要有：/net/ipv4/ip_forward.c </div> <div><span style="font-size: 12pt;">ip_fragment.c ip_input.c ip_output.c etc.</span><br /><br /><strong style="font-size: 12pt;">数据链路层和驱动程序：</strong>每个网络设备以struct net_device表示，通用的处理在dev.c中，驱动程序都在/driver/net目</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">录下。</span></div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">2.</strong><span style="font-size: 12pt;"> </span><strong style="font-size: 12pt;">两台主机建立udp通信所走过的函数列表</strong></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">^</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys_read&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fs/read_write.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock_read&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/socket.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock_recvmsg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/socket.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inet_recvmsg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/af_inet.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;udp_recvmsg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/udp.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;skb_recv_datagram&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/core/datagram.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock_queue_rcv_skb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include/net/sock.h</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;udp_queue_rcv_skb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/udp.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;udp_rcv&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/udp.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip_local_deliver_finish net/ipv4/ip_input.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip_local_deliver&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/ip_input.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip_recv&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/ip_input.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net_rx_action&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/dev.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;netif_rx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/dev.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;el3_rx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driver/net/3c309.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;el3_interrupt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driver/net/3c309.c</span><br /><br /><span style="font-size: 12pt;">＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝</span><br /><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sys_write&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fs/read_write.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock_writev&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/socket.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock_sendmsg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/socket.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inet_sendmsg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/af_inet.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;udp_sendmsg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/udp.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip_build_xmit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/ip_output.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output_maybe_reroute&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/ip_output.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip_output&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/ip_output.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip_finish_output&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/ipv4/ip_output.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dev_queue_xmit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;net/dev.c</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--------------------------------------------</span><br /><span style="font-size: 12pt;">|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;el3_start_xmit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;driver/net/3c309.c</span><br /><span style="font-size: 12pt;">V</span></div> <div>&nbsp;</div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">3.</strong> <strong>网络路径图、重要数据结构sk_buffer及路由介绍</strong></div> <div><strong></strong>&nbsp;</div> <div><strong>&nbsp;&nbsp;&nbsp;&nbsp;</strong><span style="font-size: 12pt;">linux-net.pdf 第2.1章 第2.3章 第2.4章</span></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;</div> <div><strong style="font-size: 12pt;">4.</strong> <strong>从连接、发送、到接收数据包的过程</strong></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;linux-net.pdf 第4、5、6章详细阐述</span></div> <div>&nbsp;</div> <div>&nbsp;</div> <div><strong style="font-size: 14pt;">二.linux的tcp-ip栈代码的详细分析<br /><br /></strong></div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">1.数据结构(msghdr,sk_buff,socket,sock,proto_ops,proto)</strong></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">bsd套接字层,操作的对象是socket,数据存放在msghdr这样的数据结构：</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">创建socket需要传递family,type,protocol三个参数，创建socket其实就是创建一个socket实例，然后创建一 个文件描述符结构，并且互相建立一些关联，即建立互相连接的指针，并且初始化这些对文件的写读操作映射到socket的read，write函数上来。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">同时初始化socket的操作函数（proto_ops结构),如果传入的type参数是STREAM类型，那么就初始化为 SOCKET-&gt;ops为inet_stream_ops，如果是DGRAM类型，则SOCKET-ops为inet_dgram_ops。对于 inet_stream_ops其实是一个结构体，包含了stream类型的socket操作的一些入口函数，在这些函数里主要做的是对socket进行 相关的操作，同时通过调用下面提到的sock中的相关操作完成socket到sock层的传递。比如在inet_stream_ops里有个 inet_release的操作，这个操作除了释放socket的类型空间操作外，还通过调用socket连接的sock的close操作，对于 stream类型来说，即tcp_close来关闭sock</span></div> <div><span style="font-size: 12pt;">释放sock。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">创建socket同时还创建sock数据空间，初始化sock,初始化过程主要做的事情是初始化三个队列，receive_queue（接收到 的数据包sk_buff链表队列),send_queue(需要发送数据包的sk_buff链表队列),backlog_queue(主要用于tcp中三 次握手成功的那些数据包,自己猜的),根据family、type参数，初始化sock的操作，比如对于family为inet类型的，type为 stream类型的，sock-&gt;proto初始化为tcp_prot.其中包括stream类型的协议sock操作对应的入口函数。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">在一端对socket进行write的过程中，首先会把要write的字符串缓冲区整理成msghdr的数据结构形式(参见linux内核 2.4版源代码分析大全),然后调用sock_sendmsg把msghdr的数据传送至inet层，对于msghdr结构中数据区中的每个数据包，创建 sk_buff结构，填充数据，挂至发送队列。一层层往下层协议传递。一下每层协议不再对数据进行拷贝。而是对sk_buff结构进行操作。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">inet套接字及以下层 数据存放在sk_buff这样的数据结构里：</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">路由：</span></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;在linux的路由系统主要保存了三种与路由相关的数据，第一种是在物理上和本机相连接的主机地址信息表，第二种是保存了在网络访问中判断一个网络地址应该走什么路由的数据表；第三种是最新使用过的查询路由地址的缓存地址数据表。</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;1.neighbour结构 &nbsp;neighbour_table{  }是一个包含和本机所连接的所有邻元素的信息的数据结构。该结构中有个元素是neighbour结构的数组，数组的每一个元素都是一个对应于邻机的 neighbour结构，系统中由于协议的不同，会有不同的判断邻居的方式，每种都有neighbour_table{}类型的实例，这些实例是通过 neighbour_table{}中的指针next串联起来的。在neighbour结构中，包含有与该邻居相连的网络接口设备net_device的 指针，网络接口的硬件地址，邻居的硬件地址，包含有neigh_ops{}指针，这些函数指针是直接用来连接传输数据的，包含有 queue_xmit(struct * sk_buff)函数入口地址，这个函数可能会调用硬件驱动程序的发送函数。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 2.FIB结构  在FIB中保存的是最重要的路由规则,通过对FIB数据的查找和换算，一定能够获得路由一个地址的方法。系统中路由一般采取的手段是：先到路由缓存中查找 表项，如果能够找到，直接对应的一项作为路由的规则；如果不能找到，那么就到FIB中根据规则换算传算出来，并且增加一项新的，在路由缓存中将项目添加进 去。</span></div>  <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; 3.route结构（即路由缓存中的结构)</span></div> <div>&nbsp;</div> <div>&nbsp;</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">数据链路层：</span></div> <div>&nbsp;&nbsp; </div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;  net_device{}结构，对应于每一个网络接口设备。这个结构中包含很多可以直接获取网卡信息的函数和变量，同时包含很多对于网卡操作的函数，这些 直接指向该网卡驱动程序的许多函数入口，包括发送接收数据帧到缓冲区等。当这些完成后，比如数据接收到缓冲区后便由netif_rx(在net/core /dev.c各种设备驱动程序的上层框架程序)把它们组成sk_buff形式挂到系统接收的backlog队列然后交由上层网络协议处理。同样，对于上层 协议处理下来的那些sk_buff。便由dev_queue_xmit函数放入网络缓冲区，交给网卡驱动程序的发送程序处理。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;  在系统中存在一张链表dev_base将系统中所有的net_device{}结构连在一起。对应于内核初始化而言，系统启动时便为每个所有可能支持的网 络接口设备申请了一个net_device{}空间并串连起来，然后对每个接点运行检测过程，如果检测成功，则在dev_base链表中保留这个接点，否 则删除。对应于模块加载来说，则是调用register_netdev()注册net_device,在这个函数中运行检测过程，如果成功，则加到 dev_base链表。否则就返回检测不到信息。删除同理，调用</span></div> <div><span style="font-size: 12pt;">unregister_netdev。</span></div> <div>&nbsp;</div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">2.启动分析</strong></div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;2.1 初始化进程</strong> ：start-kernel(main.c)----&gt;do_basic_setup(main.c)----&gt;sock_init(/net/socket.c)----&gt;do_initcalls(main.c)</div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">void __init sock_init(void)<br /></strong>{<br />&nbsp;int i;</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;printk(KERN_INFO "Linux NET4.0 for Linux 2.4\n");</span><br /><span style="font-size: 12pt;">&nbsp;printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n");</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Initialize all address (protocol) families.  每一项表示的是针对一个地址族的操作集合，例如对于ipv4来说，在net/ipv4/af_inet.c文件中的函数 inet_proto_init()就调用sock_register()函数将inet_families_ops初始化到属于IPV4的 net_families数组中的一项。</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br />&nbsp; <br /><span style="font-size: 12pt;">&nbsp;for (i = 0; i &lt; NPROTO; i++) </span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;net_families[i] = NULL;&nbsp;&nbsp;</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Initialize sock SLAB cache.初始化对于sock结构预留的内存的slab缓存。</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br />&nbsp; <br /><span style="font-size: 12pt;">&nbsp;sk_init();</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">#ifdef SLAB_SKB</span><br /><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Initialize skbuff SLAB cache 初始化对于skbuff结构的slab缓存。以后对于skbuff的申请可以通过函数kmem_cache_alloc()在这个缓存中申请空间。</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br /><span style="font-size: 12pt;">&nbsp;skb_init();</span><br /><span style="font-size: 12pt;">#endif</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Wan router layer. </span><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">#ifdef CONFIG_WAN_ROUTER&nbsp; </span><br /><span style="font-size: 12pt;">&nbsp;wanrouter_init();</span><br /><span style="font-size: 12pt;">#endif</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Initialize the protocols module.&nbsp;向系统登记sock文件系统，并且将其安装到系统上来。</span><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;register_filesystem(&amp;sock_fs_type);</span><br /><span style="font-size: 12pt;">&nbsp;sock_mnt = kern_mount(&amp;sock_fs_type);</span><br /><span style="font-size: 12pt;">&nbsp;/* The real protocol initialization is performed when</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp; do_initcalls is run.&nbsp; </span><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div><br /><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; * The netlink device handler may be needed early.</span><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">#ifdef CONFIG_NET</span><br /><span style="font-size: 12pt;">&nbsp;rtnetlink_init();</span><br /><span style="font-size: 12pt;">#endif</span><br /><span style="font-size: 12pt;">#ifdef CONFIG_NETLINK_DEV</span><br /><span style="font-size: 12pt;">&nbsp;init_netlink();</span><br /><span style="font-size: 12pt;">#endif</span><br /><span style="font-size: 12pt;">#ifdef CONFIG_NETFILTER</span><br /><span style="font-size: 12pt;">&nbsp;netfilter_init();</span><br /><span style="font-size: 12pt;">#endif</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">#ifdef CONFIG_BLUEZ</span><br /><span style="font-size: 12pt;">&nbsp;bluez_init();</span><br /><span style="font-size: 12pt;">#endif</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">/*yfhuang ipsec*/</span><br /><span style="font-size: 12pt;">#ifdef CONFIG_IPSEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br /><span style="font-size: 12pt;">&nbsp;pfkey_init();</span><br /><span style="font-size: 12pt;">#endif</span><br /><span style="font-size: 12pt;">/*yfhuang ipsec*/</span><br /><span style="font-size: 12pt;">}</span></div> <div><strong></strong>&nbsp;</div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;2.2 do_initcalls()</strong>&nbsp;中做了其它的初始化，其中包括</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;协议初始化，路由初始化，网络接口设备初始化</span></div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">(例如inet_init函数以_init开头表示是系统初始化时做，函数结束后跟 module_init(inet_init),这是一个宏，在include/linux/init.c中定义，展开为 _initcall(inet_init),表示这个函数在do_initcalls被调用了)</strong></div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;2.3 协议初始化</strong></div> <div><strong style="font-size: 12pt;">此处主要列举inet协议的初始化过程。</strong></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">static int __init inet_init(void)</span><br /><span style="font-size: 12pt;">{</span><br /><span style="font-size: 12pt;">&nbsp;struct sk_buff *dummy_skb;</span><br /><span style="font-size: 12pt;">&nbsp;struct inet_protocol *p;</span><br /><span style="font-size: 12pt;">&nbsp;struct inet_protosw *q;</span><br /><span style="font-size: 12pt;">&nbsp;struct list_head *r;</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n");</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;if (sizeof(struct inet_skb_parm) &gt; sizeof(dummy_skb-&gt;cb)) {</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;printk(KERN_CRIT "inet_proto_init: panic\n");</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;return -EINVAL;</span><br /><span style="font-size: 12pt;">&nbsp;}</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Tell SOCKET that we are alive...&nbsp;注册socket，告诉socket inet类型的地址族已经准备好了</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br />&nbsp;&nbsp; <br /><span style="font-size: 12pt;">&nbsp; &nbsp;(void) sock_register(&amp;inet_family_ops);</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Add all the protocols. 包括arp,ip、ICMP、UPD、tcp_v4、tcp、igmp的初始化，主要初始化各种协议对应的inode和socket变量。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">其中arp_init完成系统中路由部分neighbour表的初始化</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">ip_init完成ip协议的初始化。在这两个函数中，都通过定义一个packet_type结构的变量将这种数据包对应的协议发送数据、允许发送设备都做初始化。</span></div> <div><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;printk(KERN_INFO "IP Protocols: ");</span><br /><span style="font-size: 12pt;">&nbsp;for (p = inet_protocol_base; p != NULL;) {</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;struct inet_protocol *tmp = (struct inet_protocol *) p-&gt;next;</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;inet_add_protocol(p);</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;printk("%s%s",p-&gt;name,tmp?", ":"\n");</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;p = tmp;</span><br /><span style="font-size: 12pt;">&nbsp;}</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/* Register the socket-side information for inet_create. */</span><br /><span style="font-size: 12pt;">&nbsp;for(r = &amp;inetsw[0]; r &lt; &amp;inetsw[SOCK_MAX]; ++r)</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;INIT_LIST_HEAD(r);</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;for(q = inetsw_array; q &lt; &amp;inetsw_array[INETSW_ARRAY_LEN]; ++q)</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;inet_register_protosw(q);</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Set the ARP module up&nbsp; </span><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;arp_init();</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp; &nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; &nbsp; *&nbsp;Set the IP module up</span><br /><span style="font-size: 12pt;">&nbsp; &nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;ip_init();</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;tcp_v4_init(&amp;inet_family_ops);</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/* Setup TCP slab cache for open requests. */</span><br /><span style="font-size: 12pt;">&nbsp;tcp_init();</span></div> <div><br /><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Set the ICMP layer up</span><br /><span style="font-size: 12pt;">&nbsp; */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;icmp_init(&amp;inet_family_ops);</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/* I wish inet_add_protocol had no constructor hook...</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp; I had to move IPIP from net/ipv4/protocol.c :-( --ANK</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br /><span style="font-size: 12pt;">#ifdef CONFIG_NET_IPIP</span><br /><span style="font-size: 12pt;">&nbsp;ipip_init();</span><br /><span style="font-size: 12pt;">#endif</span><br /><span style="font-size: 12pt;">#ifdef CONFIG_NET_IPGRE</span><br /><span style="font-size: 12pt;">&nbsp;ipgre_init();</span><br /><span style="font-size: 12pt;">#endif</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Initialise the multicast router</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br /><span style="font-size: 12pt;">#if defined(CONFIG_IP_MROUTE)</span><br /><span style="font-size: 12pt;">&nbsp;ip_mr_init();</span><br /><span style="font-size: 12pt;">#endif</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;/*</span><br /><span style="font-size: 12pt;">&nbsp; *&nbsp;Create all the /proc entries.</span><br /><span style="font-size: 12pt;">&nbsp; */</span><br /><span style="font-size: 12pt;">#ifdef CONFIG_PROC_FS</span><br /><span style="font-size: 12pt;">&nbsp;proc_net_create ("raw", 0, raw_get_info);</span><br /><span style="font-size: 12pt;">&nbsp;proc_net_create ("netstat", 0, netstat_get_info);</span><br /><span style="font-size: 12pt;">&nbsp;proc_net_create ("snmp", 0, snmp_get_info);</span><br /><span style="font-size: 12pt;">&nbsp;proc_net_create ("sockstat", 0, afinet_get_info);</span><br /><span style="font-size: 12pt;">&nbsp;proc_net_create ("tcp", 0, tcp_get_info);</span><br /><span style="font-size: 12pt;">&nbsp;proc_net_create ("udp", 0, udp_get_info);</span><br /><span style="font-size: 12pt;">#endif&nbsp;&nbsp;/* CONFIG_PROC_FS */</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;ipfrag_init();</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;return 0;</span><br /><span style="font-size: 12pt;">}&nbsp;&nbsp;&nbsp;</span></div> <div><span style="font-size: 12pt;">module_init(inet_init);</span></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div> <div>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;"> 2.4 路由初始化(包括neighbour表、FIB表、和路由缓存表的初始化工作)</strong></div> <div><strong></strong>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;">2.4.1 rtcache表 ip_rt_init()函数 在net/ipv4/ip_output中调用，net/ipv4/route.c中定义</strong></div> <div><strong></strong>&nbsp;</div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;">2.4.2 FIB初始化 在ip_rt_init()中调用 在net/ipv4/fib_front.c中定义</strong></div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.4.3 neigbour表初始化&nbsp;&nbsp;arp_init（）函数中定义&nbsp;</strong></div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.5 网络接口设备初始化</strong></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在系统中网络接口都是由一个dev_base链表进行管理的。通过内核的启动方式也是通过这个链表进行操作的。在系 统启动之初，将所有内核能够支持的网络接口都初始化成这个链表中的一个节点，并且每个节点都需要初始化出init函数指针，用来检测网络接口设备。然后， 系统遍历整个dev_base链表，对每个节点分别调用init函数指针，如果成功，证明网络接口设备可用，那么这个节点就可以进一步初始化，如果返回失 败，那么证明该网络设备不存在或是不可用，只能将该节点删除。启动结束之后，在dev_base中剩下的都是可以用的网络接口设备。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.5.1  do_initcalls----&gt;net_dev_init()(net/core /dev.c)------&gt;ethif_probe()(drivers/net/Space.c,在netdevice{}结构的init中调 用，这边ethif_probe是以太网卡针对的调用)</span></div> <div>&nbsp;</div> <div><strong></strong>&nbsp;</div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">3.网络设备驱动程序（略)</strong></div> <div><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong></div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">4.网络连接</strong></div> <div><strong></strong>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.1 连接的建立和关闭</strong></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tcp连接建立的代码如下:</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server=gethostbyname(SERVER_NAME);</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockfd=socket(AF_INET,SOCK_STREAM,0);</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address.sin_family=AF_INET；</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address.sin_port=htons(PORT_NUM);</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memcpy(&amp;address.sin_addr,server-&gt;h_addr,server-&gt;h_length);</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connect(sockfd,&amp;address,sizeof(address));</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;连接的初始化与建立期间主要发生的事情如下：</span></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1）sys_socket调用：调用socket_creat(),创建出一个满足传入参数family、type、和 protocol的socket,调用sock_map_fd()获取一个未被使用的文件描述符，并且申请并初始化对应的file{}结构。</span></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2）sock_creat()：创建socket结构，针对每种不同的family的socket结构的初始化，就需要调用不同 的create函数来完成。对应于inet类型的地址来说，在网络协议初始化时调用sock_register()函数中完成注册的定义如下：</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct net_proto_family inet_family_ops={</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PF_INET;</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inet_create</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};所以inet协议最后会调用inet_create函数。</span></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3）inet_create:  初始化sock的状态设置为SS_UNCONNECTED,申请一个新的sock结构，并且初始化socket的成员ops初始化为 inet_stream_ops,而sock的成员prot初始化为tcp_prot。然后调用sock_init_data,将该socket结构的变 量sock和sock类型的变量关联起来。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4）在系统初始化完毕后便是进行connect的工作，系统调用connect将一个和socket结构关联的文件描述符和一个 sockaddr{}结构的地址对应的远程机器相关联，并且调用各个协议自己对应的connect连接函数。对应于tcp类型，则 sock-&gt;ops-&gt;connect便为inet_stream_connect。</span></div> <div>&nbsp;</div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5）inet_stream_connect:  得到sk,sk=sock-&gt;sk,锁定sk，对自动获取sk的端口号存放在sk-&gt;num中，并且用htons()函数转换存放在sk-&amp; gt;sport中。然后调用sk-&gt;prot-&gt;connect()函数指针，对tcp协议来说就是tcp_v4_connect()函 数。然后将sock-&gt;state状态字设置为SS_CONNECTING,等待后面一系列的处理完成之后，就将状态改成 SS_CONNECTTED。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6)  tcp_v4_connect()：调用函数ip_route_connect()，寻找合适的路由存放在rt中。ip_route_connect找两 次，第一次找到下一跳的ip地址，在路由缓存或fib中找到，然后第二次找到下一跳的具体邻居，到neigh_table中找到。然后申请出tcp头的空 间存放在buff中。将sk中相关地址数据做一些针对路由的变动，并且初始化一个tcp连接的序列号，调用函数tcp_connect（），初始化tcp 头，并设置tcp处理需要的定时器。一次connect（）建立的过程就结束了。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;连接的关闭主要如下：</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1）close: 一个socket文件描述符对应的file{}结构中，有一个file_operations{}结构的成员f_ops，它的初始化关闭函数为sock_close函数。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2）sock_close：调用函数sock_release(),参数为一个socket{}结构的指针。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3）sock_release：调用inet_release，并释放socket的指针和文件空间</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4）inet_release: 调用和该socket对应协议的关闭函数inet_release,如果是tcp协议，那么调用的是tcp_close；最后释放sk。</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.2 </span><strong style="font-size: 12pt;">数据发送流程图</strong></div> <div><strong></strong>&nbsp;</div> <div>&nbsp;<img alt="" src="http://blog.csdn.net/images/blog_csdn_net/cz_hyf/send.gif" usemap="#mymap" border="0" /></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">各层主要函数以及位置功能说明：</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)sock_write：初始化msghdr{}结构 net/socket.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)sock_sendmsg:net/socket.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3)inet_sendmsg:net/ipv4/af_net.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4)tcp_sendmsg：申请sk_buff{}结构的空间，把msghdr{}结构中的数据填入sk_buff空间。net/ipv4/tcp.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5)tcp_send_skb:net/ipv4/tcp_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6)tcp_transmit_skb:net/ipv4/tcp_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7)ip_queue_xmit:net/ipv4/ip_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8)ip_queue_xmit2:net/ipv4/ip_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9)ip_output:net/ipv4/ip_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10)ip_finish_output:net/ipv4/ip_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;11)ip_finish_output2:net/ipv4/ip_output.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;12)neigh_resolve_output:net/core/neighbour.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13)dev_queue_xmit:net/core/dev.c</span></div> <div>&nbsp;</div> <div>&nbsp;</div> <div><strong style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.3 数据接收流程图</strong></div> <div><img alt="" src="http://blog.csdn.net/images/blog_csdn_net/cz_hyf/receive.gif" usemap="#mymap" border="0" /></div> <div><strong></strong>&nbsp;</div> <div><span style="font-size: 12pt;">各层主要函数以及位置功能说明：</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)sock_read:初始化msghdr{}的结构类型变量msg，并且将需要接收的数据存</span><span style="font-size: 12pt;">放的地址传给msg.msg_iov-&gt;iov_base.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net/socket.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)sock_recvmsg: 调用函数指针sock-&gt;ops-&gt;recvmsg()完成在INET  Socket层的数据接收过程.其中sock-&gt;ops被初始化为inet_stream_ops,其成员recvmsg对应的函数实现为 inet_recvmsg()函数. net/socket.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3)sys_recv()/sys_recvfrom():分别对应着面向连接和面向无连接的协议两种情况. net/socket.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4)inet_recvmsg:调用sk-&gt;prot-&gt;recvmsg函数完成数据接收,这个函数对于tcp协议便是tcp_recvmsg net/ipv4/af_net.c</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5)tcp_recvmsg:从网络协议栈接收数据的动作,自上而下的触发动作一直到这个函数为止,出现了一次等待的过程.函 数tcp_recvmsg可能会被动地等待在sk的接收数据队列上,也就是说,系统中肯定有其他地方会去修改这个队列使得tcp_recvmsg可以进行 下去.入口参数sk是这个网络连接对应的sock{}指针,msg用于存放接收到的数据.接收数据的时候会去遍历接收队列中的数据,找到序列号合适的.</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;但读取队列为空时tcp_recvmsg就会调用tcp_v4_do_rcv使用backlog队列填充接收队列.</span></div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6)tcp_v4_rcv:tcp_v4_rcv被ip_local_deliver函数调用,是从IP层协议向INET  Socket层提交的"数据到"请求,入口参数skb存放接收到的数据,len是接收的数据的长度,这个函数首先移动skb-&gt;data指针,让它 指向tcp头,然后更新tcp层的一些数据统计,然后进行tcp的一些值的校验.再从INET  Socket层中已经建立的sock{}结构变量中查找正在等待当前到达数据的哪一项.可能这个sock{}结构已经建立,或者还处于监听端口、等待数据 连接的状态。返回的sock结构指针存放在sk中。然后根据其他进程对sk的操作情况,将skb发送到合适的位置.调用如下:</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCP包接收器(tcp_v4_rcv)将TCP包投递到目的套接字进行接收处理.  当套接字正被用户锁定,TCP包将暂时排入该套接字的后备队列(sk_add_backlog).这时如果某一用户线程企图锁定该套接字 (lock_sock),该线程被排入套接字的后备处理等待队列(sk-&gt;lock.wq).当用户释放上锁的套接字时 (release_sock,在tcp_recvmsg中调用),后备队列中的TCP包被立即注入TCP包处理器(tcp_v4_do_rcv)进行处 理,然后唤醒等待队列中最先的一个用户来获得其锁定权. 如果套接字未被上锁,当用户正在读取该套接字时,  TCP包将被排入套接字的预备队列(tcp_prequeue),将其传递到该用户线程上下文中进行处理.如果添加到sk-&gt;prequeue不成 功,便可以添加到 sk-&gt;receive_queue队列中(用户线程可以登记到预备队列,当预备队列中出现第一个包时就唤醒等待线程.)&nbsp;&nbsp;  /net/tcp_ipv4.c</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7)ip_rcv、ip_rcv_finish:从以太网接收数据，放到skb里，作ip层的一些数据及选项检查，调用 ip_route_input()做路由处理,判断是进行ip转发还是将数据传递到高一层的协议.调用skb-&gt;dst-&gt;input函数指 针,这个指针的实现可能有多种情况,如果路由得到的结果说明这个数据包应该转发到其他主机,这里的input便是ip_forward;如果数据包是给本 机的,那么input指针初始化为ip_local_deliver函数./net/ipv4/ip_input.c</span></div> <div>&nbsp;</div> <div><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8)ip_local_deliver、ip_local_deliver_finish:入口参数skb存放需要传送到上层 协议的数据,从ip头中获取是否已经分拆的信息,如果已经分拆,则调用函数ip_defrag将数据包重组。然后通过调用 ip_prot-&gt;handler指针调用tcp_v4_rcv(tcp)。ip_prot是inet_protocol结构指针,是用来ip层登 记协议的，比如由udp,tcp,icmp等协议。 /net/ipv4/ip_input.c</span></div></div></div><img src ="http://www.cppblog.com/finehai/aggbug/172589.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-24 13:50 <a href="http://www.cppblog.com/finehai/archive/2012/04/24/172589.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gnu binutils(addr2line ar gprof nm objcopy ...)</title><link>http://www.cppblog.com/finehai/archive/2012/04/24/172557.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Tue, 24 Apr 2012 02:28:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/24/172557.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/172557.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/24/172557.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/172557.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/172557.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: GNU binutils是一组二进制工具集。包括：addr2line ar gprof nm objcopy objdump ranlib size strings strip. 本文归纳他们的常用法。&nbsp;&nbsp;<a href='http://www.cppblog.com/finehai/archive/2012/04/24/172557.html'>阅读全文</a><img src ="http://www.cppblog.com/finehai/aggbug/172557.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-24 10:28 <a href="http://www.cppblog.com/finehai/archive/2012/04/24/172557.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[linux]探索Linux启动过程</title><link>http://www.cppblog.com/finehai/archive/2009/07/17/90335.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Fri, 17 Jul 2009 06:10:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2009/07/17/90335.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/90335.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2009/07/17/90335.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/90335.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/90335.html</trackback:ping><description><![CDATA[<p>罗列一篇，方便我等菜鸟来温习和查阅,以Solaris为例</p>
<p>
<p>按下电源，首先是BIOS取得系统控制权，BIOS进行最初的引导工作,然后交控制权交给引导分区，由引导分区加载内核并调用start_kernel函数。</p>
<p><strong>内核首先引导核心数据结构的初始化，在start_kernel函数中完成如下工作：</strong></p>
<ul xmlns:dw="http://www.ibm.com/developerworks/" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <li>输出Linux版本信息（printk(linux_banner)）
    <li>设置与体系结构相关的环境（setup_arch()）
    <li>页表结构初始化（paging_init()）
    <li>使用"arch/alpha/kernel/entry.S"中的入口点设置系统自陷入口（trap_init()）
    <li>使用alpha_mv结构和entry.S入口初始化系统IRQ（init_IRQ()）
    <li>核心进程调度器初始化（包括初始化几个缺省的Bottom-half，sched_init()）
    <li>时间、定时器初始化（包括读取CMOS时钟、估测主频、初始化定时器中断等，time_init()）
    <li>提取并分析核心启动参数（从环境变量中读取参数，设置相应标志位等待处理，（parse_options()）
    <li>控制台初始化（为输出信息而先于PCI初始化，console_init()）
    <li>剖析器数据结构初始化（prof_buffer和prof_len变量）
    <li>核心Cache初始化（描述Cache信息的Cache，kmem_cache_init()）
    <li>延迟校准（获得时钟jiffies与CPU主频ticks的延迟，calibrate_delay()）
    <li>内存初始化（设置内存上下界和页表项初始值，mem_init()）
    <li>创建和设置内部及通用cache（"slab_cache"，kmem_cache_sizes_init()）
    <li>创建uid taskcount SLAB cache（"uid_cache"，uidcache_init()）
    <li>创建文件cache（"files_cache"，filescache_init()）
    <li>创建目录cache（"dentry_cache"，dcache_init()）
    <li>创建与虚存相关的cache（"vm_area_struct"，"mm_struct"，vma_init()）
    <li>块设备读写缓冲区初始化（同时创建"buffer_head"cache用户加速访问，buffer_init()）
    <li>创建页cache（内存页hash表初始化，page_cache_init()）
    <li>创建信号队列cache（"signal_queue"，signals_init()）
    <li>初始化内存inode表（inode_init()）
    <li>创建内存文件描述符表（"filp_cache"，file_table_init()）
    <li>检查体系结构漏洞（对于alpha，此函数为空，check_bugs()）
    <li>SMP机器其余CPU（除当前引导CPU）初始化（对于没有配置SMP的内核，此函数为空，smp_init()）
    <li>启动init过程（创建第一个核心线程，调用init()函数，原执行序列调用cpu_idle() 等待调度，init()） </li>
</ul>
<p><strong>至此start_kernel()结束，基本的核心环境已经建立起来了。 </strong></p>
<p><strong>start_kernel最后一项是启动了init函数，接着由它来完成外设的初始化</strong></p>
<ul xmlns:dw="http://www.ibm.com/developerworks/" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <li>总线初始化（比如pci_init()）
    <li>网络初始化（初始化网络数据结构，包括sk_init()、skb_init()和proto_init()三部分，在proto_init()中，将调用protocols结构中包含的所有协议的初始化过程，sock_init()）
    <li>创建bdflush核心线程（bdflush()过程常驻核心空间，由核心唤醒来清理被写过的内存缓冲区，当bdflush()由kernel_thread()启动后，它将自己命名为kflushd）
    <li>创建kupdate核心线程（kupdate()过程常驻核心空间，由核心按时调度执行，将内存缓冲区中的信息更新到磁盘中，更新的内容包括超级块和inode表）
    <li>设置并启动核心调页线程kswapd（为了防止kswapd启动时将版本信息输出到其他信息中间，核心线调用kswapd_setup()设置kswapd运行所要求的环境，然后再创建 kswapd核心线程）
    <li>创建事件管理核心线程（start_context_thread()函数启动context_thread()过程，并重命名为keventd）
    <li>设备初始化（包括并口parport_init()、字符设备chr_dev_init()、块设备 blk_dev_init()、SCSI设备scsi_dev_init()、网络设备net_dev_init()、磁盘初始化及分区检查等等，device_setup()）
    <li>执行文件格式设置（binfmt_setup()）
    <li>启动任何使用__initcall标识的函数（方便核心开发者添加启动函数，do_initcalls()）
    <li>文件系统初始化（filesystem_setup()）
    <li>安装root文件系统（mount_root()） </li>
</ul>
<p><strong>这些步骤结束后，init()搜索文件系统中的init程序，并创建它，也就是我们通常所说的init进程，它是系统所有进程的起点，进程ID=1。</strong></p>
<p>在启动了的Solaris下，利用 "$ps -p 1" 可以查看该进程，输出如下：</p>
<p>PID TTY TIME CMD<br>1 ? 0:01 init<br></p>
<p><strong>接下来init进程读取/etc/inittab文件，来决定下一步如何做。</strong></p>
<p>inittab是以行为单位的描述性（非执行性）文本，每一个指令行都具有以下格式：</p>
<p><strong>id:runlevel:action:process</strong> 其中id为入口标识符，runlevel为运行级别，action为动作代号，process为具体的执行程序。</p>
<p><strong>id</strong>一般要求4个字符以内，<strong>runlevel</strong>是<strong>init</strong>所处于的运行级别的标识，一般使用0－6以及S或s（S或s表示单用户模式）。</p>
<p>action字段则告诉init进程，如何对待process字段指定的进程：当inittab中各行的runlevel值与当前运行级别匹配时，指定的action才被执行。</p>
<p>但有几个特殊的action：</p>
<p>initdefault是一个特殊的action值，用于标识缺省的启动级别；当init由核心激活以后，<strong>它将首先读取inittab中的initdefault项</strong>，取得其中的runlevel，并作为当前的运行级别。</p>
<p>sysinit、boot、bootwait等action将在系统启动时无条件运行，而忽略其中的runlevel，即不管当前运行级别是什么，它都执行，并且是优先执行。其余的action（不含initdefault）都与某个runlevel相关。</p>
<p>我的Solaris9中的/etc/inittab如下</p>
<p>ap::sysinit:/sbin/autopush -f /etc/iu.ap #action=sysinit, 该行不管在什么运行级别下，都运行<br>ap::sysinit:/sbin/soconfig -f /etc/sock2path #同上<br>fs::sysinit:/sbin/rcS sysinit &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br console&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;="" ="">is:3:initdefault: #该行action=initdefault，表明系统的默认运行级别是3<br>p3:s1234:powerfail:/usr/sbin/shutdown -y -i5 -g0 &gt;/dev/msglog 2&lt;&gt;/dev/msglog<br>sS:s:wait:/sbin/rcS &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">s0:0:wait:/sbin/rc0 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">s1:1:respawn:/sbin/rc1 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">s2:23:wait:/sbin/rc2 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">s3:3:wait:/sbin/rc3 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">s5:5:wait:/sbin/rc5 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">s6:6:wait:/sbin/rc6 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">fw:0:wait:/sbin/uadmin 2 0 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">of:5:wait:/sbin/uadmin 2 6 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">rb:6:wait:/sbin/uadmin 2 1 &gt;/dev/msglog 2&lt;&gt;/dev/msglog <br ="">sc:234:respawn:/usr/lib/saf/sac -t 300 #在2,3,4运行级别下都执行<br>co:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` console login: " -T sun -d /dev/console -l console -m ldterm,ttcompat</p>
<p>去man inittab吧，什么都讲了 :)</p>
<p>接着看我的inittab文件，当action=sysinit的行执行完之后（前三行），将执行runlevel=3的行，即&#8220; s3:3:wait:/sbin/rc3 &#8221;。查找了一下，/sbin/rc3是一个shell脚本，用于初始化在运行级别3的系统。因此/etc/inittab中已经定义好了在运行级别X下，就运行 /sbin/rcX，那/sbin/rcX到底是什么？</p>
<p>cat一下/sbin/rc3，看看，重要的几行代码如下：</p>
<p>[ $_INIT_PREV_LEVEL = 2 -o $_INIT_PREV_LEVEL = 4 ] &amp;&amp; \<br>echo 'Changing to state 3.' #如果以前运行级别是2或4，则打印信息&#8220;切换到状态三&#8221;</p>
<p>#如果运行级别!=4而且存在/etc/rc3.d这个目录，则停掉所有以K开始的脚本中的服务或程序，启动所有以S开始的脚本中的服务或程序</p>
<p>if [ $_INIT_PREV_LEVEL != 4 -a -d /etc/rc3.d ]; then<br>for f in /etc/rc3.d/K*; do<br>if [ -s $f ]; then<br>case $f in<br>*.sh) . $f ;;<br>*) /sbin/sh $f stop ;;<br>esac<br>fi<br>done</p>
<p>for f in /etc/rc3.d/S*; do<br>if [ -s $f ]; then<br>case $f in<br>*.sh) . $f ;;<br>*) /sbin/sh $f start ;;<br>esac<br>fi<br>done<br>fi</p>
<p><br><strong>那就再追踪到/etc/rc3.d下面去，</strong></p>
<p>#cd /etc/rc3.d</p>
<p>K42amserver S13kdc.master S15nfs.server S34dhcp S50apache S52imq S77dmi S81volmgt S89sshd<br>README S14kdc S16boot.server S42amserver S50san_driverchk S76snmpdx S80mipagent S84appserv S90samba<br></p>
<p>哦，都是些程序或进程的启动脚本，<span class=postbody><font size=2>S开头是启动脚本 K开头是停止脚本。这正是/sbin/rc3这个shell脚本中设定的执行方式。</font></span></p>
<p><span class=postbody><font size=2>例如：S90samba 代表一个启动samba服务的脚本，90表示启动顺序编号。</font></span><span class=postbody><font size=2> K42amserver代表结束服务的脚本。</font></span></p>
<p>
<p><font size=2><strong>rc程序执行完毕后，系统环境已经设置好了，下面就该用户登录系统了，终于结束了。</strong></font></p>
<img src ="http://www.cppblog.com/finehai/aggbug/90335.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2009-07-17 14:10 <a href="http://www.cppblog.com/finehai/archive/2009/07/17/90335.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>