网络协议栈1:socket函数调用之前

client代码中,第一个被调用的函数是socket(),在这个函数被调用之前,系统做了什么事情,让socket()可以正常调用?

 

首先,socket函数实际上是一个系统调用,它是内核中的代码,我们应用层通过系统调用,调用了系统的函数。

其次,在系统启动时,已经调用sock_init()对socket进行了初始化,在我们调用socket函数之前,socket的初始化部分已经为我们的调用做好的铺垫了。

void sock_init(void)
{
      int i;

      ......

      for (i = 0; i < NPROTO; ++i) pops[i] = NULL;

     proto_init();

     ......

}

其中 #define NPROTO  16  /* should be enough for now.. */

pops[i]在初始化时,首先被  for (i = 0; i < NPROTO; ++i) pops[i] = NULL; 语句清空,再被proto_init();函数填充上对应的值

 

void proto_init(void)
{
 extern struct net_proto protocols[]; /* Network protocols */
 struct net_proto *pro;

 /* Kick all configured protocols. */
 pro = protocols;
 while (pro->name != NULL)
 {
  (*pro->init_func)(pro);
  pro++;
 }
 /* We're all done... */
}

其中的

 while (pro->name != NULL)
 {
  (*pro->init_func)(pro);
  pro++;
 }

调用对应协议的初始化函数,来填充pops[ ]数组的某一项

 

具体道TCP/IP协议,(*pro->init_func) (pro)就是 执行了protocols[] 这个数组中的inet_proto_init函数来初始化的

struct net_proto protocols[] = {

……

#ifdef  CONFIG_INET

  { "INET",     inet_proto_init     },

#endif

……

}

inet_proto_init()函数又调用了sock_registe()函数来注册

sock_register又被inet_proto_init()函数调用,用于把数组的指针记录到pops[ ] 全局变量中

int sock_register(int family, struct proto_ops *ops)

{

……

(void) sock_register(inet_proto_ops.family, &inet_proto_ops);

……

 }

int sock_register(int family, struct proto_ops *ops)

{

      int i;

 

      cli();

      for(i = 0; i < NPROTO; i++)

      {

            if (pops[i] != NULL)

                 continue;

           pops[i] = ops;

           pops[i]->family = family;

           sti();

           return(i);

      }

      sti();

      return(-ENOMEM);

}

pops[i] = ops;就是初始化pops [ ] 全局数组的地方了,其中,net_proto_ops定义如下

static struct proto_ops inet_proto_ops = {
 AF_INET,

 inet_create,
 inet_dup,
 inet_release,
 inet_bind,
 inet_connect,
 inet_socketpair,
 inet_accept,
 inet_getname,
 inet_read,
 inet_write,
 inet_select,
 inet_ioctl,
 inet_listen,
 inet_send,
 inet_recv,
 inet_sendto,
 inet_recvfrom,
 inet_shutdown,
 inet_setsockopt,
 inet_getsockopt,
 inet_fcntl,
};

其实就是定义了一堆函数,并用这些函数来初始化数组,将来使用这个函数来完成具体的任务。

 

回过头看,socket初始化所做的事,就是把各个协议所对应的操作集登记在一个全局数组中,为我们后面的应用程序调用socket()创建套接字做好准备,因为我们在使用static int sock_socket(int family, int type, int protocol)函数创建套接字时,通过int family这个参数,指定了所需要的协议,通过这个协议,就能扫描pops [ ]全局数据,找到这个数组中的对应的函数来完成我们的工作。

posted on 2012-01-05 10:37  image eye  阅读(2649)  评论(0编辑  收藏  举报