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 [ ]全局数据,找到这个数组中的对应的函数来完成我们的工作。