套接字实现

linux支持多种不同的符合OSI模型的通信协议。协议模块分为多组协议族和套接字类型如下图:


            套接字有两个抽象的层次,一个是socket一个是sock。

套接字与sock结构相关联,包含于特定协议族和类型相关的域。sock数据结构中的域指向特定协议族的数据,包括特定协议的函数集合、控制标志、特定协议信息的数据指针。

            socket()系统调用仅标识每个协议族和类型的函数集合,并对套接字和sock数据结构进行初始化。sock对象有一个prot域,该域指向协议相关的操作集。

 

1.1.1 协议注册

sock_register函数(位于net/socket.c中),入参为net_proto_family,在系统初始化阶段为协议族添加套接字的接口。对于INET而言就是inet_family_ops。

inet_create函数是创建INET协议族套接字的调用函数。这个函数在sock_register()中赋值给struct net_proto_family中的create函数指针。

net_families[]是全局数组,用来注册网族套接字。

inetsw是在系统初始化时候初始化的数组,通过套接字类型(SOCK_STREAM)索引。

inet_register_protosw()函数位于net/ipv4/af_inet.c文件中, 注册inet套接字的回调函数

inetsw_array是一个全局静态数组,对象是结构体inet_protosw,结构体static struct inet_protosw inetsw_array[]已经定义如下,系统在初始化的时候会读取inetsw_array来填写inetsw数组(在网络初始化inet_init函数中,调用inet_register_protosw函数来完成),因此系统中所有inet套接字都在inetsw数组中。

static struct inet_protosw inetsw_array[] =

{

        {               

                .type =       SOCK_STREAM,

                .protocol =   IPPROTO_TCP,

                .prot =       &tcp_prot, 

                .ops =        &inet_stream_ops,

                .flags =      INET_PROTOSW_PERMANENT | 

                              INET_PROTOSW_ICSK,       

        },              

 

        {               

                .type =       SOCK_DGRAM,

                .protocol =   IPPROTO_UDP,

                .prot =       &udp_prot, 

                .ops =        &inet_dgram_ops,

                .flags =      INET_PROTOSW_PERMANENT,  

       },               

 

       {

                .type =       SOCK_DGRAM,

                .protocol =   IPPROTO_ICMP,

                .prot =       &ping_prot,

                .ops =        &inet_sockraw_ops,       

                .flags =      INET_PROTOSW_REUSE,

       },

 

       {

               .type =       SOCK_RAW,  

               .protocol =   IPPROTO_IP,        /* wild card */

               .prot =       &raw_prot, 

               .ops =        &inet_sockraw_ops,       

               .flags =      INET_PROTOSW_REUSE,

       }

};

如下图

     

 

1.1.2 创建sock

inet_protosw结构体定义如下:

定义在文件include/net/protocol.h中:

/* This is used to register socket interfaces for IP protocols.  */

struct inet_protosw {

        struct list_head list; 

 

        /* These two fields form the lookup key.  */

        unsigned short   type;     /* This is the 2nd argument to socket(2). */

        unsigned short   protocol; /* This is the L4 protocol number.  */

       

        struct proto     *prot;

        const struct proto_ops *ops;

 

        unsigned char    flags;      /* See INET_PROTOSW_* below.  */

};

            其中prot是proto结构的指针,该结构包含特定于IP协议(如TCP/UDP)的函数集合(close,connect,accept,bind),例如tcp_prot与SOCK_STREAM相对应,udp_prot与SOCK_DGRAM相对应。IP协议块在结构proto帮助下,实现与套接字结合。

ops是指向proto_ops类型结构的指针,包含特定协议族的函数集,和prot类似,不过是套接字层的函数。inet_stream_ops与SOCK_STREAM对应,inet_dgram_ops与SOCK_DGRAM对应。一旦调用与套接字相关的系统调用,首先调用proto_ops结构体中的相应函数,然后调用proto结构中相应IP协议相关的函数。

 

1.1.3 套接字创建

以tcp套接字为例,其创建过程如下:

socket->sys_socket->sock_create->inet_create(net_families[family]->create())->sock_init_data()->(sk->prot->init=tcp_v4_init_sock())->tcp_init_xmit_timers()->tcp_prequeue_init()

sock_create(位于net/socket.c文件中)调用__sock_create,用于初始化套接字相关的sock结构体。

            实现过程如下图所示:


             套接字这块和协议初始化存在较大相关性,不得不涉及了初始化相关的内容,后面单独会看协议栈的初始化工作,并使其具有层次感。

猜你喜欢

转载自blog.csdn.net/notbaron/article/details/79884197