网络编程常用API

来源:互联网 发布:云计算开发招聘 编辑:程序博客网 时间:2024/05/01 23:08

1socket(family,type,protocol)

当我们在开发网络应用程序时,使用该系统调用来创建一个套接字。该API所做的工作如下所示:

struct socket {

         socket_state             state;  //socket状态

         unsigned long           flags; //标识,如SOCK_ASYNC_NOSAPCE

         const struct proto_ops  *ops; //协议特定的socket操作集

         struct fasync_struct         *fasync_list; //异步唤醒队列

         struct file                   *file; //指向文件的指针

         struct sock                *sk; //指向下一层中的sock结构

         wait_queue_head_t         wait; //等待在这个socket上的任务列表

         short                           type; //数据包的类型

  };

  在创建socket套接字时,就是要完成ops、file和sk等这些成员的初始化。

 1). 创建套接字:sock_create()

函数sock_create会调用__sock_create函数进行套接字的创建:

  1. int __sock_create(struct net *net, int family, int type, int protocol,  
  2.              struct socket **res, int kern)  
  3. {  
  4.     int err;  
  5.     struct socket *sock;  
  6.     const struct net_proto_family *pf;  
  7.   
  8.     /* 
  9.      *      合法性检查 
  10.      */  
  11.     if (family < 0 || family >= NPROTO)  
  12.         return -EAFNOSUPPORT;  
  13.     if (type < 0 || type >= SOCK_MAX)  
  14.         return -EINVAL;  
  15.   
  16.     /* Compatibility. 
  17.  
  18.        This uglymoron is moved from INET layer to here to avoid 
  19.        deadlock in module load. 
  20.      */  
  21.     if (family == PF_INET && type == SOCK_PACKET) {  
  22.         static int warned;  
  23.         if (!warned) {  
  24.             warned = 1;  
  25.             printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",  
  26.                    current->comm);  
  27.         }  
  28.         family = PF_PACKET;  
  29.     }  
  30.   
  31.     err = security_socket_create(family, type, protocol, kern);  
  32.     if (err)  
  33.         return err;  
  34.   
  35.     sock = sock_alloc();//分配inode结构并获得对应的socket结构  
  36.     if (!sock) {  
  37.         if (net_ratelimit())  
  38.             printk(KERN_WARNING "socket: no more sockets\n");  
  39.         return -ENFILE; /* Not exactly a match, but its the 
  40.                    closest posix thing */  
  41.     }  
  42.   
  43.     sock->type = type;  
  44.   
  45.     rcu_read_lock();  
  46.     pf = rcu_dereference(net_families[family]);  
  47.     err = -EAFNOSUPPORT;  
  48.     if (!pf)  
  49.         goto out_release;  
  50.   
  51.     /* 
  52.      * We will call the ->create function, that possibly is in a loadable 
  53.      * module, so we have to bump that loadable module refcnt first. 
  54.      */  
  55.     if (!try_module_get(pf->owner))//模块检测  
  56.         goto out_release;  
  57.   
  58.     /* Now protected by module ref count */  
  59.     rcu_read_unlock();  
  60.   
  61.     //这里调用inet_create函数对INET协议族进行创建  
  62.     err = pf->create(net, sock, protocol, kern);  
  63.     if (err < 0)  
  64.         goto out_module_put;  
  65.   
  66.     /* 
  67.      * Now to bump the refcnt of the [loadable] module that owns this 
  68.      * socket at sock_release time we decrement its refcnt. 
  69.      */  
  70.     if (!try_module_get(sock->ops->owner))  
  71.         goto out_module_busy;  
  72.   
  73.     /* 
  74.      * Now that we're done with the ->create function, the [loadable] 
  75.      * module can have its refcnt decremented 
  76.      */  
  77.     module_put(pf->owner);  
  78.     err = security_socket_post_create(sock, family, type, protocol, kern);  
  79.     if (err)  
  80.         goto out_sock_release;  
  81.     *res = sock;  
  82.   
  83.     return 0;  
  84.   
  85. out_module_busy:  
  86.     err = -EAFNOSUPPORT;  
  87. out_module_put:  
  88.     sock->ops = NULL;  
  89.     module_put(pf->owner);  
  90. out_sock_release:  
  91.     sock_release(sock);  
  92.     return err;  
  93.   
  94. out_release:  
  95.     rcu_read_unlock();  
  96.     goto out_sock_release;  
  97. }  
其中的参数protocol的取值如下:

[cpp] view plaincopy
  1. /* Standard well-defined IP protocols.  */  
  2. enum {  
  3.   IPPROTO_IP = 0,       /* Dummy protocol for TCP       */  
  4.   IPPROTO_ICMP = 1,     /* Internet Control Message Protocol    */  
  5.   IPPROTO_IGMP = 2,     /* Internet Group Management Protocol   */  
  6.   IPPROTO_IPIP = 4,     /* IPIP tunnels (older KA9Q tunnels use 94) */  
  7.   IPPROTO_TCP = 6,      /* Transmission Control Protocol    */  
  8.   IPPROTO_EGP = 8,      /* Exterior Gateway Protocol        */  
  9.   IPPROTO_PUP = 12,     /* PUP protocol             */  
  10.   IPPROTO_UDP = 17,     /* User Datagram Protocol       */  
  11.   IPPROTO_IDP = 22,     /* XNS IDP protocol         */  
  12.   IPPROTO_DCCP = 33,        /* Datagram Congestion Control Protocol */  
  13.   IPPROTO_RSVP = 46,        /* RSVP protocol            */  
  14.   IPPROTO_GRE = 47,     /* Cisco GRE tunnels (rfc 1701,1702)    */  
  15.   
  16.   IPPROTO_IPV6   = 41,      /* IPv6-in-IPv4 tunnelling      */  
  17.   
  18.   IPPROTO_ESP = 50,            /* Encapsulation Security Payload protocol */  
  19.   IPPROTO_AH = 51,             /* Authentication Header protocol       */  
  20.   IPPROTO_BEETPH = 94,         /* IP option pseudo header for BEET */  
  21.   IPPROTO_PIM    = 103,     /* Protocol Independent Multicast   */  
  22.   
  23.   IPPROTO_COMP   = 108,                /* Compression Header protocol */  
  24.   IPPROTO_SCTP   = 132,     /* Stream Control Transport Protocol    */  
  25.   IPPROTO_UDPLITE = 136,    /* UDP-Lite (RFC 3828)          */  
  26.   
  27.   IPPROTO_RAW    = 255,     /* Raw IP packets           */  
  28.   IPPROTO_MAX  
  29. };  
INET层socket(inet_socket)和传输层socket(struct sock)创建

函数inet_create完成了上述功能,并初始化了sock的属性值,将socket的sk属性指向sock结构

[cpp] view plaincopy
  1. static int inet_create(struct net *net, struct socket *sock, int protocol,  
  2.                int kern)  
  3. {  
  4.     struct sock *sk;  
  5.     struct inet_protosw *answer;  
  6.     struct inet_sock *inet;  
  7.     struct proto *answer_prot;  
  8.     unsigned char answer_flags;  
  9.     char answer_no_check;  
  10.     int try_loading_module = 0;  
  11.     int err;  
  12.   
  13.     if (unlikely(!inet_ehash_secret))  
  14.         if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)  
  15.             build_ehash_secret();  
  16.   
  17.     sock->state = SS_UNCONNECTED;  
  18.   
  19.     /* Look for the requested type/protocol pair. */  
  20. lookup_protocol:  
  21.     err = -ESOCKTNOSUPPORT;  
  22.     rcu_read_lock();  
  23.     //根据传输层协议的类型创建sock结构  
  24.     //遍历inetsw链表  
  25.     list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {  
  26.   
  27.         err = 0;  
  28.         /* Check the non-wild match. */  
  29.         if (protocol == answer->protocol) {  
  30.             if (protocol != IPPROTO_IP)  
  31.                 break;//找到了适配的inetsw[]元素  
  32.         } else {  
  33.             /* Check for the two wild cases. */  
  34.             if (IPPROTO_IP == protocol) {  
  35.                 protocol = answer->protocol;  
  36.                 break;  
  37.             }  
  38.             if (IPPROTO_IP == answer->protocol)  
  39.                 break;  
  40.         }  
  41.         err = -EPROTONOSUPPORT;  
  42.     }  
  43.     //到这里answer指向了合适的inetsw结构,若是TCP协议,answer指向内容如下  
  44.     /* 
  45.     *   .type =       SOCK_STREAM, 
  46.     *   .protocol =   IPPROTO_TCP, 
  47.     *   .prot =       &tcp_prot, 
  48.     *   .ops =        &inet_stream_ops, 
  49.     *   .no_check =   0, 
  50.     *   .flags =      INET_PROTOSW_PERMANENT | 
  51.     *             INET_PROTOSW_ICSK, 
  52.     */  
  53.     if (unlikely(err)) {  
  54.         if (try_loading_module < 2) {  
  55.             rcu_read_unlock();  
  56.             /* 
  57.              * Be more specific, e.g. net-pf-2-proto-132-type-1 
  58.              * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM) 
  59.              */  
  60.             if (++try_loading_module == 1)  
  61.                 request_module("net-pf-%d-proto-%d-type-%d",  
  62.                            PF_INET, protocol, sock->type);  
  63.             /* 
  64.              * Fall back to generic, e.g. net-pf-2-proto-132 
  65.              * (net-pf-PF_INET-proto-IPPROTO_SCTP) 
  66.              */  
  67.             else  
  68.                 request_module("net-pf-%d-proto-%d",  
  69.                            PF_INET, protocol);  
  70.             goto lookup_protocol;  
  71.         } else  
  72.             goto out_rcu_unlock;  
  73.     }  
  74.   
  75.     err = -EPERM;  
  76.     if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))  
  77.         goto out_rcu_unlock;  
  78.   
  79.     err = -EAFNOSUPPORT;  
  80.     if (!inet_netns_ok(net, protocol))  
  81.         goto out_rcu_unlock;  
  82.   
  83.     sock->ops = answer->ops;  
  84.     answer_prot = answer->prot;  
  85.     answer_no_check = answer->no_check;  
  86.     answer_flags = answer->flags;  
  87.     rcu_read_unlock();  
  88.   
  89.     WARN_ON(answer_prot->slab == NULL);  
  90.   
  91.     err = -ENOBUFS;  
  92.     //分配sock结构体内存,这里在inet_init函数初始化好的高速缓冲区中分配内存,然后做一些初始化工作。后面有进一步分析。  
  93.     sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);  
  94.     if (sk == NULL)  
  95.         goto out;  
  96.   
  97.     err = 0;  
  98.     sk->sk_no_check = answer_no_check;  
  99.     if (INET_PROTOSW_REUSE & answer_flags)  
  100.         sk->sk_reuse = 1;  
  101.   
  102.     inet = inet_sk(sk);//后面有进一步分析,为何可以强制转换?!!  
  103.     inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;  
  104.   
  105.     inet->nodefrag = 0;  
  106.   
  107.     if (SOCK_RAW == sock->type) {  
  108.         inet->inet_num = protocol;  
  109.         if (IPPROTO_RAW == protocol)  
  110.             inet->hdrincl = 1;  
  111.     }  
  112.   
  113.     if (ipv4_config.no_pmtu_disc)  
  114.         inet->pmtudisc = IP_PMTUDISC_DONT;  
  115.     else  
  116.         inet->pmtudisc = IP_PMTUDISC_WANT;  
  117.   
  118.     inet->inet_id = 0;  
  119.     //对sk进行初始化设置并将sock中的sk指针指向sk结构  
  120.     sock_init_data(sock, sk);  
  121.   
  122.     //进一步设置sk的其他属性信息  
  123.     sk->sk_destruct     = inet_sock_destruct;  
  124.     sk->sk_protocol     = protocol;  
  125.     sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;  
  126.   
  127.     inet->uc_ttl = -1;  
  128.     inet->mc_loop    = 1;  
  129.     inet->mc_ttl = 1;  
  130.     inet->mc_all = 1;  
  131.     inet->mc_index   = 0;  
  132.     inet->mc_list    = NULL;  
  133.   
  134.     sk_refcnt_debug_inc(sk);  
  135.   
  136.     if (inet->inet_num) {  
  137.         /* It assumes that any protocol which allows 
  138.          * the user to assign a number at socket 
  139.          * creation time automatically 
  140.          * shares. 
  141.          */  
  142.         inet->inet_sport = htons(inet->inet_num);  
  143.         /* Add to protocol hash chains. */  
  144.         sk->sk_prot->hash(sk);//调用inet_hash函数  
  145.     }  
  146.       
  147.     if (sk->sk_prot->init) {  
  148.         err = sk->sk_prot->init(sk);//调用tcp_v4_init_sock函数进行进一步的初始化,由于在函数sk_alloc中一些属性被设置成0了,所以在此调用进行初始化  
  149.         if (err)  
  150.             sk_common_release(sk);  
  151.     }  
  152. out:  
  153.     return err;  
  154. out_rcu_unlock:  
  155.     rcu_read_unlock();  
  156.     goto out;  
  157. }     

  158.     

根据family参数值在全局数组struct net_proto_family net_families[]里找到我们所指定的地址簇。

其中inetsw_array[]是一个比较重要的数据结构,定义在af_inet.c文件中:

在初始化的时候我们会将上面数组中的的元素按套接字类型插入inetsw链表数组中。其定义如下:

[cpp] view plaincopy
  1. static struct list_head inetsw[SOCK_MAX];  

不同类型的地址簇都有一个struct net_proto_family{}类型的对象,例如我们常见的IPv4的inet_family_ops,IPv6的inet6_family_ops,X25协议的ax25_family_ops等。在内核是初始化时,这些模块会在自己的初始化函数内部调用sock_register()接口将各自的地址簇对象注册到net_families[]数组里。

       我们分析的焦点集中在IPv4协议簇,即inet_family_ops对象上。重点是inet_create函数,该函数的主要任务就是创建一个socket套接字,并对其中相关结构体成员进行必要的初始化。至于它创建套接字时的依据和原理等到我们讲协议栈时大家就明白了,这里主要是让大家对其流程执行流程有个感性的把握。

       sock_alloc()函数中我们创建一个struct socket{}类型的对象,假如叫做A,将socket()系统调用的第二参数type字段赋值给A->type。

       在inet_create()函数中,我们根据type的值,在全局数组struct inet_protosw inetsw[]里找到我们对应的协议转换开关。而inetsw[]数组是在inet_init()函数里被初始化的:

      根据type的值,就可以确定struct socket{}->ops,到底是inet_stream_ops、inet_dgram_ops或者inet_sockraw_ops。

TCP协议z在INET层操作集inet_stream_ops

  1. const struct proto_ops inet_stream_ops = {  
  2.     .family        = PF_INET,  
  3.     .owner         = THIS_MODULE,  
  4.     .release       = inet_release,  
  5.     .bind          = inet_bind,  
  6.     .connect       = inet_stream_connect,  
  7.     .socketpair    = sock_no_socketpair,  
  8.     .accept        = inet_accept,  
  9.     .getname       = inet_getname,  
  10.     .poll          = tcp_poll,  
  11.     .ioctl         = inet_ioctl,  
  12.     .listen        = inet_listen,  
  13.     .shutdown      = inet_shutdown,  
  14.     .setsockopt    = sock_common_setsockopt,  
  15.     .getsockopt    = sock_common_getsockopt,  
  16.     .sendmsg       = inet_sendmsg,  
  17.     .recvmsg       = inet_recvmsg,  
  18.     .mmap          = sock_no_mmap,  
  19.     .sendpage      = inet_sendpage,  
  20.     .splice_read       = tcp_splice_read,  
  21. #ifdef CONFIG_COMPAT  
  22.     .compat_setsockopt = compat_sock_common_setsockopt,  
  23.     .compat_getsockopt = compat_sock_common_getsockopt,  
  24.     .compat_ioctl      = inet_compat_ioctl,  
  25. #endif  
  26. };  
UDP协议在INET层操作集inet_dgram_ops
[cpp] view plaincopy
  1. const struct proto_ops inet_dgram_ops = {  
  2.     .family        = PF_INET,  
  3.     .owner         = THIS_MODULE,  
  4.     .release       = inet_release,  
  5.     .bind          = inet_bind,  
  6.     .connect       = inet_dgram_connect,  
  7.     .socketpair    = sock_no_socketpair,  
  8.     .accept        = sock_no_accept,  
  9.     .getname       = inet_getname,  
  10.     .poll          = udp_poll,  
  11.     .ioctl         = inet_ioctl,  
  12.     .listen        = sock_no_listen,  
  13.     .shutdown      = inet_shutdown,  
  14.     .setsockopt    = sock_common_setsockopt,  
  15.     .getsockopt    = sock_common_getsockopt,  
  16.     .sendmsg       = inet_sendmsg,  
  17.     .recvmsg       = inet_recvmsg,  
  18.     .mmap          = sock_no_mmap,  
  19.     .sendpage      = inet_sendpage,  
  20. #ifdef CONFIG_COMPAT  
  21.     .compat_setsockopt = compat_sock_common_setsockopt,  
  22.     .compat_getsockopt = compat_sock_common_getsockopt,  
  23.     .compat_ioctl      = inet_compat_ioctl,  
  24. #endif  
  25. };  

然后,对应地,就以tcp_prot、udp_prot或raw_prot为输入参数,

  1. struct proto tcp_prot = {  
  2.     .name           = "TCP",  
  3.     .owner          = THIS_MODULE,  
  4.     .close          = tcp_close,  
  5.     .connect        = tcp_v4_connect,  
  6.     .disconnect     = tcp_disconnect,  
  7.     .accept         = inet_csk_accept,  
  8.     .ioctl          = tcp_ioctl,  
  9.     .init           = tcp_v4_init_sock,  
  10.     .destroy        = tcp_v4_destroy_sock,  
  11.     .shutdown       = tcp_shutdown,  
  12.     .setsockopt     = tcp_setsockopt,  
  13.     .getsockopt     = tcp_getsockopt,  
  14.     .recvmsg        = tcp_recvmsg,  
  15.     .sendmsg        = tcp_sendmsg,  
  16.     .sendpage       = tcp_sendpage,  
  17.     .backlog_rcv        = tcp_v4_do_rcv,  
  18.     .hash           = inet_hash,  
  19.     .unhash         = inet_unhash,  
  20.     .get_port       = inet_csk_get_port,  
  21.     .enter_memory_pressure  = tcp_enter_memory_pressure,  
  22.     .sockets_allocated  = &tcp_sockets_allocated,  
  23.     .orphan_count       = &tcp_orphan_count,  
  24.     .memory_allocated   = &tcp_memory_allocated,  
  25.     .memory_pressure    = &tcp_memory_pressure,  
  26.     .sysctl_mem     = sysctl_tcp_mem,  
  27.     .sysctl_wmem        = sysctl_tcp_wmem,  
  28.     .sysctl_rmem        = sysctl_tcp_rmem,  
  29.     .max_header     = MAX_TCP_HEADER,  
  30.     .obj_size       = sizeof(struct tcp_sock),  
  31.     .slab_flags     = SLAB_DESTROY_BY_RCU,  
  32.     .twsk_prot      = &tcp_timewait_sock_ops,  
  33.     .rsk_prot       = &tcp_request_sock_ops,  
  34.     .h.hashinfo     = &tcp_hashinfo,  
  35.     .no_autobind        = true,  
  36. #ifdef CONFIG_COMPAT  
  37.     .compat_setsockopt  = compat_tcp_setsockopt,  
  38.     .compat_getsockopt  = compat_tcp_getsockopt,  
  39. #endif  
  40. };  

  1. struct proto udp_prot = {  
  2.     .name          = "UDP",  
  3.     .owner         = THIS_MODULE,  
  4.     .close         = udp_lib_close,  
  5.     .connect       = ip4_datagram_connect,  
  6.     .disconnect    = udp_disconnect,  
  7.     .ioctl         = udp_ioctl,  
  8.     .destroy       = udp_destroy_sock,  
  9.     .setsockopt    = udp_setsockopt,  
  10.     .getsockopt    = udp_getsockopt,  
  11.     .sendmsg       = udp_sendmsg,  
  12.     .recvmsg       = udp_recvmsg,  
  13.     .sendpage      = udp_sendpage,  
  14.     .backlog_rcv       = __udp_queue_rcv_skb,  
  15.     .hash          = udp_lib_hash,  
  16.     .unhash        = udp_lib_unhash,  
  17.     .rehash        = udp_v4_rehash,  
  18.     .get_port      = udp_v4_get_port,  
  19.     .memory_allocated  = &udp_memory_allocated,  
  20.     .sysctl_mem    = sysctl_udp_mem,  
  21.     .sysctl_wmem       = &sysctl_udp_wmem_min,  
  22.     .sysctl_rmem       = &sysctl_udp_rmem_min,  
  23.     .obj_size      = sizeof(struct udp_sock),  
  24.     .slab_flags    = SLAB_DESTROY_BY_RCU,  
  25.     .h.udp_table       = &udp_table,  
  26. #ifdef CONFIG_COMPAT  
  27.     .compat_setsockopt = compat_udp_setsockopt,  
  28.     .compat_getsockopt = compat_udp_getsockopt,  
  29. #endif  
  30.     .clear_sk      = sk_prot_clear_portaddr_nulls,  
  31. };  

实例化一个struct sock{} 对象sk=sk_alloc()。

  1. struct sock {  
  2.     /* 
  3.      * Now struct inet_timewait_sock also uses sock_common, so please just 
  4.      * don't add nothing before this first member (__sk_common) --acme 
  5.      */  
  6.     struct sock_common  __sk_common;  
  7. #define sk_node         __sk_common.skc_node  
  8. #define sk_nulls_node       __sk_common.skc_nulls_node  
  9. #define sk_refcnt       __sk_common.skc_refcnt  
  10. #define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping  
  11.   
  12. #define sk_dontcopy_begin   __sk_common.skc_dontcopy_begin  
  13. #define sk_dontcopy_end     __sk_common.skc_dontcopy_end  
  14. #define sk_hash         __sk_common.skc_hash  
  15. #define sk_family       __sk_common.skc_family  
  16. #define sk_state        __sk_common.skc_state  
  17. #define sk_reuse        __sk_common.skc_reuse  
  18. #define sk_bound_dev_if     __sk_common.skc_bound_dev_if  
  19. #define sk_bind_node        __sk_common.skc_bind_node  
  20. #define sk_prot         __sk_common.skc_prot  
  21. #define sk_net          __sk_common.skc_net  
  22.     socket_lock_t       sk_lock;  
  23.     struct sk_buff_head sk_receive_queue;  
  24.     /* 
  25.      * The backlog queue is special, it is always used with 
  26.      * the per-socket spinlock held and requires low latency 
  27.      * access. Therefore we special case it's implementation. 
  28.      * Note : rmem_alloc is in this structure to fill a hole 
  29.      * on 64bit arches, not because its logically part of 
  30.      * backlog. 
  31.      */  
  32.     struct {  
  33.         atomic_t    rmem_alloc;  
  34.         int     len;  
  35.         struct sk_buff  *head;  
  36.         struct sk_buff  *tail;  
  37.     } sk_backlog;  
  38. #define sk_rmem_alloc sk_backlog.rmem_alloc  
  39.     int         sk_forward_alloc;  
  40. #ifdef CONFIG_RPS  
  41.     __u32           sk_rxhash;  
  42. #endif  
  43.     atomic_t        sk_drops;  
  44.     int         sk_rcvbuf;  
  45.   
  46.     struct sk_filter __rcu  *sk_filter;  
  47.     struct socket_wq __rcu  *sk_wq;  
  48.   
  49. #ifdef CONFIG_NET_DMA  
  50.     struct sk_buff_head sk_async_wait_queue;  
  51. #endif  
  52.   
  53. #ifdef CONFIG_XFRM  
  54.     struct xfrm_policy  *sk_policy[2];  
  55. #endif  
  56.     unsigned long       sk_flags;  
  57.     struct dst_entry    *sk_dst_cache;  
  58.     spinlock_t      sk_dst_lock;  
  59.     atomic_t        sk_wmem_alloc;  
  60.     atomic_t        sk_omem_alloc;  
  61.     int         sk_sndbuf;  
  62.     struct sk_buff_head sk_write_queue;  
  63.     kmemcheck_bitfield_begin(flags);  
  64.     unsigned int        sk_shutdown  : 2,  
  65.                 sk_no_check  : 2,  
  66.                 sk_userlocks : 4,  
  67.                 sk_protocol  : 8,  
  68.                 sk_type      : 16;  
  69.     kmemcheck_bitfield_end(flags);  
  70.     int         sk_wmem_queued;  
  71.     gfp_t           sk_allocation;  
  72.     int         sk_route_caps;  
  73.     int         sk_route_nocaps;  
  74.     int         sk_gso_type;  
  75.     unsigned int        sk_gso_max_size;  
  76.     int         sk_rcvlowat;  
  77.     unsigned long           sk_lingertime;  
  78.     struct sk_buff_head sk_error_queue;  
  79.     struct proto        *sk_prot_creator;  
  80.     rwlock_t        sk_callback_lock;  
  81.     int         sk_err,  
  82.                 sk_err_soft;  
  83.     unsigned short      sk_ack_backlog;  
  84.     unsigned short      sk_max_ack_backlog;  
  85.     __u32           sk_priority;  
  86.     struct pid      *sk_peer_pid;  
  87.     const struct cred   *sk_peer_cred;  
  88.     long            sk_rcvtimeo;  
  89.     long            sk_sndtimeo;  
  90.     void            *sk_protinfo;  
  91.     struct timer_list   sk_timer;  
  92.     ktime_t         sk_stamp;  
  93.     struct socket       *sk_socket;  
  94.     void            *sk_user_data;  
  95.     struct page     *sk_sndmsg_page;  
  96.     struct sk_buff      *sk_send_head;  
  97.     __u32           sk_sndmsg_off;  
  98.     int         sk_write_pending;  
  99. #ifdef CONFIG_SECURITY  
  100.     void            *sk_security;  
  101. #endif  
  102.     __u32           sk_mark;  
  103.     u32         sk_classid;  
  104.     void            (*sk_state_change)(struct sock *sk);  
  105.     void            (*sk_data_ready)(struct sock *sk, int bytes);  
  106.     void            (*sk_write_space)(struct sock *sk);  
  107.     void            (*sk_error_report)(struct sock *sk);  
  108.     int         (*sk_backlog_rcv)(struct sock *sk,  
  109.                           struct sk_buff *skb);    
  110.     void                    (*sk_destruct)(struct sock *sk);  
  111. };  

紧接着建立socket{}和sock{}的关联,最后将socket()系统调用的第三个参数protocol付给sock{}对象中的属性sk_protocol。 

       2). 为套接字绑定文件句柄:sock_map_fd()

       我们都知道网络套接字也是一种系统IO,所以不可避免的要与文件系统打交道。每个套接字都对应一个已打开的文件标识符,所以在套接字初始化完成后,就要将其和本地一个唯一的文件标识符关联起来,即建立socket{}和file{}之间的关联关系。

 

       2、bind (sockfd, sockaddr, addrlen)

       该系统调用在内核中的执行过程如下:

       重点是socket->ops->bind()回调接口。我们现在已经知道了,针对IPv4而言,这里的ops无非就是inet_stream_opsinet_dgram_opsinet_sockraw_ops对象。碰巧的是,这三个对象中的bind函数指针均指向inet_bind()函数。只有原始套接字的情况,这里会去调用raw_prot对象的bind回调函数,即raw_bind()。

 

       3、listen(sockfd, backlog)

       这里我们可以看到面向无连接的套接字和原始套接字是不用listen的,只有流式套接字才有效。

 

       4、connect(sockfd, sockaddr, addrlen)

       从这幅图中我们确实看到,connect()系统调用不但可以面向连接的套接字,也可用于无连接及原始套接字。

 

       5、accept(sockfd, sockaddr, addrlen)

       同样地,我们看到只有面向连接的流式套接字调用accept()才有意义。最终调用的是tcp_prot对象的accept成员函数。

       补充::

为什么内核中可以直接将sock结构体首地址强制转换成inet_sock的首地址?并且inet_sock的大小要大于sock,直接进行如下强制转换

[cpp] view plaincopy
  1. inet = inet_sk(sk);  

[cpp] view plaincopy
  1. static inline struct inet_sock *inet_sk(const struct sock *sk)  
  2. {  
  3.     return (struct inet_sock *)sk;  
  4. }  

不会发生内存非法访问吗?!那就是在分配的时候并不只是分配的struct sock结构体大小的存储空间!

可以细看sock结构体分配的代码:

[cpp] view plaincopy
  1. struct sock *sk_alloc(struct net *net, int family, gfp_t priority,  
  2.               struct proto *prot)  
  3. {  
  4.     struct sock *sk;  
  5.   
  6.     sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);  
  7.     if (sk) {  
  8.         sk->sk_family = family;  
  9.         sk->sk_prot = sk->sk_prot_creator = prot;  
  10.         sock_lock_init(sk);  
  11.         sock_net_set(sk, get_net(net));  
  12.         atomic_set(&sk->sk_wmem_alloc, 1);  
  13.   
  14.         sock_update_classid(sk);  
  15.     }  
  16.   
  17.     return sk;  
  18. }  
紧接着调用sk_prot_alloc函数分配:

[cpp] view plaincopy
  1. static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,  
  2.         int family)  
  3. {  
  4.     struct sock *sk;  
  5.     struct kmem_cache *slab;  
  6.   
  7.     slab = prot->slab;  
  8.     if (slab != NULL) {  
  9.         sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO);  
  10.         ..............................  
  11.     } else  
  12.         sk = kmalloc(prot->obj_size, priority);  
  13.   
  14.     .....................  
  15.   
  16.     return sk;  
  17. ......................  
  18. }  
上面的代码中首先判断高速缓存中是否可用,如果不可用,直接在内存分配空间,不过大小都是prot->obj_size。

如果是TCP协议中的tcp_prot中指明该属性的大小为.obj_size = sizeof(struct tcp_sock)。

所以,程序中给struct sock指针分配的不是该结构体的实际大小,而是大于其实际大小,以便其扩展套接字的属性占用。
以图例说明tcp_sock是如何从sock强制转换来的:


       


原创粉丝点击