Linux网络协议栈(一)——Socket入门(2)

http://www.cnblogs.com/hustcat/archive/2009/09/17/1568765.html

3、套接字的实现
套接字最先是在UNIX的BSD版本实现的,所以也叫做BSD套接字,它隐藏了各个协议之间的差异,并向上提供统一的接口。Linux中实现套接字的基本结构:

3.1、BSD套接字
3.1.1、核心数据结构
为了实现BSD套接字,内核提供一个重要的数据结构struct socket,它的定义如下:

复制代码
  // BSD套接字(include/linux/net.h)
struct  socket {
    socket_state        state;  
// 套接字状态
    unsigned  long         flags;
    
struct  proto_ops     * ops;  // 操作函数集
     struct  fasync_struct     * fasync_list;
    
struct  file         * file; // 每个BSD套接字都有一个inode结点,通过文件对象与其关联起来  
     struct  sock         * sk;  // socket内部结构,与具体的协议簇(比如PF_INET)相关
    wait_queue_head_t    wait;
    
short             type;     // 套接字类型:如SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, and SOCK_PACKET
    unsigned  char         passcred; 
};

// BSD套接字操作函数集
struct  proto_ops {
    
int         family;
    
struct  module     * owner;
    
int         ( * release)   ( struct  socket  * sock);
    
int         ( * bind)         ( struct  socket  * sock,
                      
struct  sockaddr  * myaddr,
                      
int  sockaddr_len);
    
int         ( * connect)   ( struct  socket  * sock,
                      
struct  sockaddr  * vaddr,
                      
int  sockaddr_len,  int  flags);
    
int         ( * socketpair)( struct  socket  * sock1,
                      
struct  socket  * sock2);
    
int         ( * accept)    ( struct  socket  * sock,
                      
struct  socket  * newsock,  int  flags);
    
int         ( * getname)   ( struct  socket  * sock,
                      
struct  sockaddr  * addr,
                      
int   * sockaddr_len,  int  peer);
    unsigned 
int     ( * poll)         ( struct  file  * file,  struct  socket  * sock,
                      
struct  poll_table_struct  * wait);
    
int         ( * ioctl)     ( struct  socket  * sock, unsigned  int  cmd,
                      unsigned 
long  arg);
    
int         ( * listen)    ( struct  socket  * sock,  int  len);
    
int         ( * shutdown)  ( struct  socket  * sock,  int  flags);
    
int         ( * setsockopt)( struct  socket  * sock,  int  level,
                      
int  optname,  char  __user  * optval,  int  optlen);
    
int         ( * getsockopt)( struct  socket  * sock,  int  level,
                      
int  optname,  char  __user  * optval,  int  __user  * optlen);
    
int         ( * sendmsg)   ( struct  kiocb  * iocb,  struct  socket  * sock,
                      
struct  msghdr  * m, size_t total_len);
    
int         ( * recvmsg)   ( struct  kiocb  * iocb,  struct  socket  * sock,
                      
struct  msghdr  * m, size_t total_len,
                      
int  flags);
    
int         ( * mmap)         ( struct  file  * file,  struct  socket  * sock,
                      
struct  vm_area_struct  *  vma);
    ssize_t        (
* sendpage)  ( struct  socket  * sock,  struct  page  * page,
                      
int  offset, size_t size,  int  flags);
};
// BSD套接字状态
typedef  enum  {
    SS_FREE 
=   0 ,             /*  not allocated         */
    SS_UNCONNECTED,            
/*  unconnected to any socket     */
    SS_CONNECTING,            
/*  in process of connecting     */
    SS_CONNECTED,            
/*  connected to socket         */
    SS_DISCONNECTING        
/*  in process of disconnecting     */
} socket_state; 
复制代码
3.1.2、BSD套接字初始化
复制代码
// net/socket.c
// BSD套接字的初始化
void  __init sock_init( void )
{
    
int  i;

    
/*
     *    Initialize all address (protocol) families. 
     
*/
     
    
for  (i  =   0 ; i  <  NPROTO; i ++
        net_families[i] 
=  NULL;  // 协议簇数组初始化

    
/*
     *    Initialize sock SLAB cache.
     
*/
     
// 分配sock缓存
    sk_init();

#ifdef SLAB_SKB
    
/*
     *    Initialize skbuff SLAB cache 
     
*/
    skb_init();
#endif

    
/*
     *    Initialize the protocols module. 
     
*/

    init_inodecache();

    
// 注册sockfs文件系统
    register_filesystem( & sock_fs_type);
    
// 安装sockfs
    sock_mnt  =  kern_mount( & sock_fs_type);
    
/*  The real protocol initialization is performed when
     *  do_initcalls is run.  
     
*/

#ifdef CONFIG_NETFILTER
    netfilter_init();
#endif
}


// net/socket.c
// sockfs文件系统的安装点
static   struct  vfsmount  * sock_mnt;
// sockfs文件系统类型
static   struct  file_system_type sock_fs_type  =  {
    .name 
=          " sockfs " ,
    .get_sb 
=     sockfs_get_sb,
    .kill_sb 
=     kill_anon_super,
}; 
// 地址簇及协议信息
static   struct  net_proto_family  * net_families[NPROTO]; 
复制代码
sock_init在系统初始化的被调用:

3.1.3、BSD套接字的系统调用
实际上,Linux内核只提供了一个与套接字相关的系统调用,即sys_socketcall,应用程序的所有套接字调用都会映射到这个系统调用上。
复制代码
// BSD套接字调用入口(net/socket.c)
asmlinkage  long  sys_socketcall( int  call, unsigned  long  __user  * args)
{
    unsigned 
long  a[ 6 ];
    unsigned 
long  a0,a1;
    
int  err;

    
if (call < 1 || call > SYS_RECVMSG)
        
return   - EINVAL;

    
/*  copy_from_user should be SMP safe.  */
    
if  (copy_from_user(a, args, nargs[call])) // 从用户区拷贝参数
         return   - EFAULT;
        
    a0
= a[ 0 ];
    a1
= a[ 1 ];
    
    
switch (call)   // 调用相应的函数
    {
        
case  SYS_SOCKET:
            err 
=  sys_socket(a0,a1,a[ 2 ]);
            
break ;
        
case  SYS_BIND:
            err 
=  sys_bind(a0,( struct  sockaddr __user  * )a1, a[ 2 ]);
            
break ;
        
case  SYS_CONNECT:
            err 
=  sys_connect(a0, ( struct  sockaddr __user  * )a1, a[ 2 ]);
            
break ;
        
case  SYS_LISTEN:
            err 
=  sys_listen(a0,a1);
            
break ;
        
case  SYS_ACCEPT:
            err 
=  sys_accept(a0,( struct  sockaddr __user  * )a1, ( int  __user  * )a[ 2 ]);
            
break ;
        
case  SYS_GETSOCKNAME:
            err 
=  sys_getsockname(a0,( struct  sockaddr __user  * )a1, ( int  __user  * )a[ 2 ]);
            
break ;
        
case  SYS_GETPEERNAME:
            err 
=  sys_getpeername(a0, ( struct  sockaddr __user  * )a1, ( int  __user  * )a[ 2 ]);
            
break ;
        
case  SYS_SOCKETPAIR:
            err 
=  sys_socketpair(a0,a1, a[ 2 ], ( int  __user  * )a[ 3 ]);
            
break ;
        
case  SYS_SEND:
            err 
=  sys_send(a0, ( void  __user  * )a1, a[ 2 ], a[ 3 ]);
            
break ;
        
case  SYS_SENDTO:
            err 
=  sys_sendto(a0,( void  __user  * )a1, a[ 2 ], a[ 3 ],
                     (
struct  sockaddr __user  * )a[ 4 ], a[ 5 ]);
            
break ;
        
case  SYS_RECV:
            err 
=  sys_recv(a0, ( void  __user  * )a1, a[ 2 ], a[ 3 ]);
            
break ;
        
case  SYS_RECVFROM:
            err 
=  sys_recvfrom(a0, ( void  __user  * )a1, a[ 2 ], a[ 3 ],
                       (
struct  sockaddr __user  * )a[ 4 ], ( int  __user  * )a[ 5 ]);
            
break ;
        
case  SYS_SHUTDOWN:
            err 
=  sys_shutdown(a0,a1);
            
break ;
        
case  SYS_SETSOCKOPT:
            err 
=  sys_setsockopt(a0, a1, a[ 2 ], ( char  __user  * )a[ 3 ], a[ 4 ]);
            
break ;
        
case  SYS_GETSOCKOPT:
            err 
=  sys_getsockopt(a0, a1, a[ 2 ], ( char  __user  * )a[ 3 ], ( int  __user  * )a[ 4 ]);
            
break ;
        
case  SYS_SENDMSG:
            err 
=  sys_sendmsg(a0, ( struct  msghdr __user  * ) a1, a[ 2 ]);
            
break ;
        
case  SYS_RECVMSG:
            err 
=  sys_recvmsg(a0, ( struct  msghdr __user  * ) a1, a[ 2 ]);
            
break ;
        
default :
            err 
=   - EINVAL;
            
break ;
    }
    
return  err;
}

// include/asm/unistd.h
#define  __NR_socketcall        102   // 系统调用号
复制代码
下面来看一下sys_socket的实现:
Code
3.2、INET套接字
INET套接字就是支持 Internet 地址族的套接字,它位于TCP协议之上, BSD套接字之下,如下:

3.2.1、数据结构

//include/net/sock.h
//与特定协议相关的socket
struct sock {
    
/*
     * Now struct tcp_tw_bucket also uses sock_common, so please just
     * don't add nothing before this first member (__sk_common) --acme
     
*/
    
struct sock_common    __sk_common;
#define sk_family        __sk_common.skc_family
#define sk_state        __sk_common.skc_state
#define sk_reuse        __sk_common.skc_reuse
#define sk_bound_dev_if        __sk_common.skc_bound_dev_if
#define sk_node            __sk_common.skc_node
#define sk_bind_node        __sk_common.skc_bind_node
#define sk_refcnt        __sk_common.skc_refcnt
    
volatile unsigned char    sk_zapped;
    unsigned 
char        sk_shutdown;
    unsigned 
char        sk_use_write_queue;
    unsigned 
char        sk_userlocks;
    socket_lock_t        sk_lock;
    
int            sk_rcvbuf;
    wait_queue_head_t    
*sk_sleep;
    
struct dst_entry    *sk_dst_cache;
    rwlock_t        sk_dst_lock;
    
struct xfrm_policy    *sk_policy[2];
    atomic_t        sk_rmem_alloc;
    
struct sk_buff_head    sk_receive_queue;
    atomic_t        sk_wmem_alloc;
    
struct sk_buff_head    sk_write_queue;
    atomic_t        sk_omem_alloc;
    
int            sk_wmem_queued;
    
int            sk_forward_alloc;
    unsigned 
int        sk_allocation;
    
int            sk_sndbuf;
    unsigned 
long         sk_flags;
    
char             sk_no_check;
    unsigned 
char        sk_debug;
    unsigned 
char        sk_rcvtstamp;
    unsigned 
char        sk_no_largesend;
    
int            sk_route_caps;
    unsigned 
long            sk_lingertime;
    
int            sk_hashent;
    
/*
     * The backlog queue is special, it is always used with
     * the per-socket spinlock held and requires low latency
     * access. Therefore we special case it's implementation.
     
*/
    
struct {
        
struct sk_buff *head;
        
struct sk_buff *tail;
    } sk_backlog;
    rwlock_t        sk_callback_lock;
    
struct sk_buff_head    sk_error_queue;
    
    
struct proto        *sk_prot;
    
    
int            sk_err,
                sk_err_soft;
    unsigned 
short        sk_ack_backlog;
    unsigned 
short        sk_max_ack_backlog;
    __u32            sk_priority;
    unsigned 
short        sk_type;
    unsigned 
char        sk_localroute;
    unsigned 
char        sk_protocol;
    
struct ucred        sk_peercred;
    
int            sk_rcvlowat;
    
long            sk_rcvtimeo;
    
long            sk_sndtimeo;
    
struct sk_filter          *sk_filter;
    
void            *sk_protinfo;
    kmem_cache_t        
*sk_slab;
    
struct timer_list    sk_timer;
    
struct timeval        sk_stamp;
    
struct socket        *sk_socket;
    
void            *sk_user_data;
    
struct module        *sk_owner;
    
struct page        *sk_sndmsg_page;
    __u32            sk_sndmsg_off;
    
struct sk_buff        *sk_send_head;
    
int            sk_write_pending;
    
void            *sk_security;
    __u8            sk_queue_shrunk;
    
/* three bytes hole, try to pack */
    
void            (*sk_state_change)(struct sock *sk);
    
void            (*sk_data_ready)(struct sock *sk, int bytes);
    
void            (*sk_write_space)(struct sock *sk);
    
void            (*sk_error_report)(struct sock *sk);
      
int            (*sk_backlog_rcv)(struct sock *sk,
                          
struct sk_buff *skb);  
    
void                    (*sk_destruct)(struct sock *sk);
};

//底层协议的操作函数
struct proto {
    
void            (*close)(struct sock *sk, 
                    
long timeout);
    
int            (*connect)(struct sock *sk,
                        
struct sockaddr *uaddr, 
                    
int addr_len);
    
int            (*disconnect)(struct sock *sk, int flags);

    
struct sock *        (*accept) (struct sock *sk, int flags, int *err);

    
int            (*ioctl)(struct sock *sk, int cmd,
                     unsigned 
long arg);
    
int            (*init)(struct sock *sk);
    
int            (*destroy)(struct sock *sk);
    
void            (*shutdown)(struct sock *sk, int how);
    
int            (*setsockopt)(struct sock *sk, int level, 
                    
int optname, char __user *optval,
                    
int optlen);
    
int            (*getsockopt)(struct sock *sk, int level, 
                    
int optname, char __user *optval, 
                    
int __user *option);       
    
int            (*sendmsg)(struct kiocb *iocb, struct sock *sk,
                       
struct msghdr *msg, size_t len);
    
int            (*recvmsg)(struct kiocb *iocb, struct sock *sk,
                       
struct msghdr *msg,
                    size_t len, 
int noblock, int flags, 
                    
int *addr_len);
    
int            (*sendpage)(struct sock *sk, struct page *page,
                    
int offset, size_t size, int flags);
    
int            (*bind)(struct sock *sk, 
                    
struct sockaddr *uaddr, int addr_len);

    
int            (*backlog_rcv) (struct sock *sk, 
                        
struct sk_buff *skb);

    
/* Keeping track of sk's, looking them up, and port selection methods. */
    
void            (*hash)(struct sock *sk);
    
void            (*unhash)(struct sock *sk);
    
int            (*get_port)(struct sock *sk, unsigned short snum);

    
/* Memory pressure */
    
void            (*enter_memory_pressure)(void);
    atomic_t        
*memory_allocated;    /* Current allocated memory. */
    atomic_t        
*sockets_allocated;    /* Current number of sockets. */
    
/*
     * Pressure flag: try to collapse.
     * Technical note: it is used by multiple contexts non atomically.
     * All the sk_stream_mem_schedule() is of this nature: accounting
     * is strict, actions are advisory and have some latency.
     
*/
    
int            *memory_pressure;
    
int            *sysctl_mem;
    
int            *sysctl_wmem;
    
int            *sysctl_rmem;
    
int            max_header;

    kmem_cache_t        
*slab;
    
int            slab_obj_size;

    
struct module        *owner;

    
char            name[32];

    
struct {
        
int inuse;
        u8  __pad[SMP_CACHE_BYTES 
- sizeof(int)];
    } stats[NR_CPUS];
};
inet_init()函数:

//net/ipv4/af_inet.c
/*
系统初始化时被调用
**调用路径:start_kernel() -->init() -->do_basic_setup() -->do_initcalls()-->inet_init()
*/
static int __init inet_init(void)
{
    
struct sk_buff *dummy_skb;
    
struct inet_protosw *q;
    
struct list_head *r;
    
int rc = -EINVAL;

    
if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
        printk(KERN_CRIT 
"%s: panic\n", __FUNCTION__);
        
goto out;
    }

    rc 
= sk_alloc_slab(&tcp_prot, "tcp_sock");
    
if (rc) {
        sk_alloc_slab_error(
&tcp_prot);
        
goto out;
    }
    rc 
= sk_alloc_slab(&udp_prot, "udp_sock");
    
if (rc) {
        sk_alloc_slab_error(
&udp_prot);
        
goto out_tcp_free_slab;
    }
    rc 
= sk_alloc_slab(&raw_prot, "raw_sock");
    
if (rc) {
        sk_alloc_slab_error(
&raw_prot);
        
goto out_udp_free_slab;
    }

    
/*
     *    Tell SOCKET that we are alive 
     
*/
    
//注册Internet协议簇的相关信息
      (void)sock_register(&inet_family_ops);

    
/*
     *    Add all the base protocols.
     
*/
    
//添加基本的协议
    if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
        printk(KERN_CRIT 
"inet_init: Cannot add ICMP protocol\n");
    
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
        printk(KERN_CRIT 
"inet_init: Cannot add UDP protocol\n");
    
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
        printk(KERN_CRIT 
"inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
    
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
        printk(KERN_CRIT 
"inet_init: Cannot add IGMP protocol\n");
#endif

    
/* Register the socket-side information for inet_create. */
    
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
        INIT_LIST_HEAD(r);
        
  
//将inetsw_array中元素加入到inetsw链表中
    for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
        inet_register_protosw(q);

    
/*
     *    Set the ARP module up
     
*/

    arp_init(); 
//ARP协议初始化

      
/*
       *    Set the IP module up
       
*/

    ip_init(); 
//IP协议初始化

    tcp_v4_init(
&inet_family_ops);

    
/* Setup TCP slab cache for open requests. */
    tcp_init();


    
/*
     *    Set the ICMP layer up
     
*/

    icmp_init(
&inet_family_ops);

    
/*
     *    Initialise the multicast router
     
*/
#if defined(CONFIG_IP_MROUTE)
    ip_mr_init();
#endif
    
/*
     *    Initialise per-cpu ipv4 mibs
     
*/ 

    
if(init_ipv4_mibs())
        printk(KERN_CRIT 
"inet_init: Cannot init ipv4 mibs\n"); ;
    
    ipv4_proc_init();

    ipfrag_init();

    rc 
= 0;
out:
    
return rc;
out_tcp_free_slab:
    sk_free_slab(
&tcp_prot);
out_udp_free_slab:
    sk_free_slab(
&udp_prot);
    
goto out;
}

//net/ipv4/af_inet.c
//INET协议簇信息
static struct net_proto_family inet_family_ops = {
    .family 
= PF_INET,
    .create 
= inet_create,
    .owner    
= THIS_MODULE,
};

static struct list_head inetsw[SOCK_MAX];
//该数组中的所有元素都会插入到inetsw的链表中
static struct inet_protosw inetsw_array[] =
{
        {
                .type 
=       SOCK_STREAM,
                .protocol 
=   IPPROTO_TCP,
                .prot 
=       &tcp_prot,
                .ops 
=        &inet_stream_ops,
                .capability 
= -1,
                .no_check 
=   0,
                .flags 
=      INET_PROTOSW_PERMANENT,
        },

        {
                .type 
=       SOCK_DGRAM,
                .protocol 
=   IPPROTO_UDP,
                .prot 
=       &udp_prot,
                .ops 
=        &inet_dgram_ops,
                .capability 
= -1,
                .no_check 
=   UDP_CSUM_DEFAULT,
                .flags 
=      INET_PROTOSW_PERMANENT,
       },
        

       {
               .type 
=       SOCK_RAW,
               .protocol 
=   IPPROTO_IP,    /* wild card */
               .prot 
=       &raw_prot,
               .ops 
=        &inet_sockraw_ops,
               .capability 
= CAP_NET_RAW,
               .no_check 
=   UDP_CSUM_DEFAULT,
               .flags 
=      INET_PROTOSW_REUSE,
       }
};

//流套接字操作函数
struct proto_ops inet_stream_ops = {
    .family 
=    PF_INET,
    .owner 
=    THIS_MODULE,
    .release 
=    inet_release,
    .bind 
=        inet_bind,
    .connect 
=    inet_stream_connect,
    .socketpair 
=    sock_no_socketpair,
    .accept 
=    inet_accept,
    .getname 
=    inet_getname,
    .poll 
=        tcp_poll,
    .ioctl 
=    inet_ioctl,
    .listen 
=    inet_listen,
    .shutdown 
=    inet_shutdown,
    .setsockopt 
=    sock_common_setsockopt,
    .getsockopt 
=    sock_common_getsockopt,
    .sendmsg 
=    inet_sendmsg,
    .recvmsg 
=    sock_common_recvmsg,
    .mmap 
=        sock_no_mmap,
    .sendpage 
=    tcp_sendpage
};
//tcp协议
static struct net_protocol tcp_protocol = {
    .handler 
=    tcp_v4_rcv,
    .err_handler 
=    tcp_v4_err,
    .no_policy 
=    1,
};

static struct net_protocol udp_protocol = {
    .handler 
=    udp_rcv,
    .err_handler 
=    udp_err,
    .no_policy 
=    1,
};

static struct net_protocol icmp_protocol = {
    .handler 
=    icmp_rcv,
};


//net/ipv4/tcp_ipv4.c
//tcp协议的操作函数
struct proto tcp_prot = {
    .name            
= "TCP",
    .owner            
= THIS_MODULE,
    .close            
= tcp_close,
    .connect        
= tcp_v4_connect,
    .disconnect        
= tcp_disconnect,
    .accept            
= tcp_accept,
    .ioctl            
= tcp_ioctl,
    .init            
= tcp_v4_init_sock,
    .destroy        
= tcp_v4_destroy_sock,
    .shutdown        
= tcp_shutdown,
    .setsockopt        
= tcp_setsockopt,
    .getsockopt        
= tcp_getsockopt,
    .sendmsg        
= tcp_sendmsg,
    .recvmsg        
= tcp_recvmsg,
    .backlog_rcv        
= tcp_v4_do_rcv,
    .hash            
= tcp_v4_hash,
    .unhash            
= tcp_unhash,
    .get_port        
= tcp_v4_get_port,
    .enter_memory_pressure    
= tcp_enter_memory_pressure,
    .sockets_allocated    
= &tcp_sockets_allocated,
    .memory_allocated    
= &tcp_memory_allocated,
    .memory_pressure    
= &tcp_memory_pressure,
    .sysctl_mem        
= sysctl_tcp_mem,
    .sysctl_wmem        
= sysctl_tcp_wmem,
    .sysctl_rmem        
= sysctl_tcp_rmem,
    .max_header        
= MAX_TCP_HEADER,
    .slab_obj_size        
= sizeof(struct tcp_sock),
};
sock_register()函数:

//注册协议簇
int sock_register(struct net_proto_family *ops)
{
    
int err;

    
if (ops->family >= NPROTO) {
        printk(KERN_CRIT 
"protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);
        
return -ENOBUFS;
    }
    net_family_write_lock();
    err 
= -EEXIST;
    
if (net_families[ops->family] == NULL) {
        net_families[ops
->family]=ops;
        err 
= 0;
    }
    net_family_write_unlock();
    printk(KERN_INFO 
"NET: Registered protocol family %d\n",
           ops
->family);
    
return err;
}
inet_create()函数

//创建一个INET套接字
static int inet_create(struct socket *sock, int protocol)
{
    
struct sock *sk;
    
struct list_head *p;
    
struct inet_protosw *answer;
    
struct inet_opt *inet;
    
struct proto *answer_prot;
    unsigned 
char answer_flags;
    
char answer_no_check;
    
int err;

    sock
->state = SS_UNCONNECTED;

    
/* Look for the requested type/protocol pair. */
    answer 
= NULL;
    rcu_read_lock();
    list_for_each_rcu(p, 
&inetsw[sock->type]) {
        answer 
= list_entry(p, struct inet_protosw, list);

        
/* Check the non-wild match. */
        
if (protocol == answer->protocol) {
            
if (protocol != IPPROTO_IP)
                
break;
        } 
else {
            
/* Check for the two wild cases. */
            
if (IPPROTO_IP == protocol) {
                protocol 
= answer->protocol;
                
break;
            }
            
if (IPPROTO_IP == answer->protocol)
                
break;
        }
        answer 
= NULL;
    }

    err 
= -ESOCKTNOSUPPORT;
    
if (!answer)
        
goto out_rcu_unlock;
    err 
= -EPERM;
    
if (answer->capability > 0 && !capable(answer->capability))
        
goto out_rcu_unlock;
    err 
= -EPROTONOSUPPORT;
    
if (!protocol)
        
goto out_rcu_unlock;
    
    
//BSD socket的操作函数
    sock->ops = answer->ops;
    answer_prot 
= answer->prot;
    
    answer_no_check 
= answer->no_check;
    answer_flags 
= answer->flags;
    rcu_read_unlock();

    BUG_TRAP(answer_prot
->slab != NULL);

    err 
= -ENOBUFS;
    sk 
= sk_alloc(PF_INET, GFP_KERNEL,
              answer_prot
->slab_obj_size,
              answer_prot
->slab);
    
if (sk == NULL)
        
goto out;

    err 
= 0;
    
//特定协议套接字的操作函数
    sk->sk_prot = answer_prot;
    sk
->sk_no_check = answer_no_check;
    
if (INET_PROTOSW_REUSE & answer_flags)
        sk
->sk_reuse = 1;

    inet 
= inet_sk(sk);

    
if (SOCK_RAW == sock->type) {
        inet
->num = protocol;
        
if (IPPROTO_RAW == protocol)
            inet
->hdrincl = 1;
    }

    
if (ipv4_config.no_pmtu_disc)
        inet
->pmtudisc = IP_PMTUDISC_DONT;
    
else
        inet
->pmtudisc = IP_PMTUDISC_WANT;

    inet
->id = 0;
    
//将sock与sk关联起来
    sock_init_data(sock, sk);
    sk_set_owner(sk, sk
->sk_prot->owner);

    sk
->sk_destruct       = inet_sock_destruct;
    sk
->sk_family       = PF_INET;
    sk
->sk_protocol       = protocol;
    sk
->sk_backlog_rcv = sk->sk_prot->backlog_rcv;

    inet
->uc_ttl    = -1;
    inet
->mc_loop    = 1;
    inet
->mc_ttl    = 1;
    inet
->mc_index    = 0;
    inet
->mc_list    = NULL;

#ifdef INET_REFCNT_DEBUG
    atomic_inc(
&inet_sock_nr);
#endif

    
if (inet->num) {
        
/* It assumes that any protocol which allows
         * the user to assign a number at socket
         * creation time automatically
         * shares.
         
*/
        inet
->sport = htons(inet->num);
        
/* Add to protocol hash chains. */
        sk
->sk_prot->hash(sk);
    }
    
//调用init函数
    if (sk->sk_prot->init) {
        err 
= sk->sk_prot->init(sk);
        
if (err)
            sk_common_release(sk);
    }
out:
    
return err;
out_rcu_unlock:
    rcu_read_unlock();
    
goto out;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值