tcp/ip协议socket创建详解

 

------------------------------------------

本文系本站原创,欢迎转载!
转载请注明出处:http://sjj0412.cublog.cn/
------------------------------------------

   要分析套接字就不的不提到inode。套接字可以和文件关联,当然是和特殊的文件系统关联,这样就可象操作文件一样操作网络,给应用程序用户提供了极大的便利。既然可以是文件操作,就少不了INODE,由于要和socket关联,那么inode中应该有于socket相关的,事实上确实如此。

struct inode {

                  union {

              struct minix_inode_info         minix_i;

              struct ext2_inode_info          ext2_i;

              struct ext3_inode_info          ext3_i;

              struct hpfs_inode_info          hpfs_i;

              struct ntfs_inode_info           ntfs_i;

              struct msdos_inode_info              msdos_i;

              struct umsdos_inode_info     umsdos_i;

              struct iso_inode_info            isofs_i;

              struct nfs_inode_info            nfs_i;

              struct sysv_inode_info          sysv_i;

              struct affs_inode_info           affs_i;

              struct ufs_inode_info            ufs_i;

              struct efs_inode_info            efs_i;

              struct romfs_inode_info        romfs_i;

              struct shmem_inode_info             shmem_i;

              struct coda_inode_info          coda_i;

              struct smb_inode_info          smbfs_i;

              struct hfs_inode_info            hfs_i;

              struct adfs_inode_info          adfs_i;

              struct qnx4_inode_info         qnx4_i;

              struct reiserfs_inode_info      reiserfs_i;

              struct bfs_inode_info            bfs_i;

              struct udf_inode_info            udf_i;

              struct ncp_inode_info           ncpfs_i;

              struct proc_inode_info          proc_i;

              struct socket                 socket_i;

              struct usbdev_inode_info        usbdev_i;

              struct jffs2_inode_info          jffs2_i;

              void                      *generic_ip;

       } u;

};

上面的u联合体中的socket_i就将socketinode联系起来了。

 

有了上面的一点基础,现在我们就以tcp协议的套接字创建为例来分析socket创建过程。

当我们在应用程序调用API函数socket(AF_INET,SOCK_RAW,IPPROTO_TCP)时就会调用socket的系统调用进入统一的入口函数sys_socketcall,如果是创建套接字,就会调用sys_socket,sys_socket然后就调用sock_create,这个才是真正执行socket创建的函数。

Sys_socketcall->sys_socket->sock_create()-

int sock_create(int family, int type, int protocol, struct socket **res)

{

………

……..

              if (!(sock = sock_alloc()))

       {

              printk(KERN_WARNING "socket: no more sockets/n");

              i = -ENFILE;         /* Not exactly a match, but its the

                                      closest posix thing */

              goto out;

       }

……..

………

}

Sock_create函数调用socket_alloc创建socket,主要分配两个主要数据,一个是套接字socket,另一个是socket对应的inode

 

Sys_socketcall->sys_socket->sock_create()->sock_alloc

 

struct socket *sock_alloc(void)

{

       struct inode * inode;

       struct socket * sock;

//为当前套接字分配Inode

       inode = get_empty_inode();

       if (!inode)

              return NULL;

    //为套接字对应的Inode指定其文件系统的超级块,这个超级块其实不存在

       //sock_mntkern_mount中创建,是具体文件系统的全局变量。

inode->i_sb = sock_mnt->mnt_sb;

    // 获取Inode对应的socket结构来初始化

       sock = socki_lookup(inode);//

 

       inode->i_mode = S_IFSOCK|S_IRWXUGO;

       inode->i_sock = 1;

       inode->i_uid = current->fsuid;

       inode->i_gid = current->fsgid;

 

       sock->inode = inode;

       init_waitqueue_head(&sock->wait);

       sock->fasync_list = NULL;

       sock->state = SS_UNCONNECTED;

       sock->flags = 0;

       sock->ops = NULL;

       sock->sk = NULL;

       sock->file = NULL;

 

       sockets_in_use[smp_processor_id()].counter++;

       return sock;

}

       首先分配SOCK文件的INODE,然后将其与sockfssb联系起来,分配inode时其实已经分配了socket结构体,因为socket结构体是inode的成员,然后就初始化Inode和对应socketSocket数据结构如下。

struct socket

{

       socket_state           state;

 

       unsigned long         flags;

       struct proto_ops     *ops;

//文件系统相关的接口file,inode

       struct inode           *inode;

       struct fasync_struct      *fasync_list;   /* Asynchronous wake up list       */

       struct file        *file;              /* File back pointer for gc     */

//网络关联的数据接口在sock

       struct sock            *sk;

       wait_queue_head_t wait;

 

       short                     type;

       unsigned char        passcred;

};

我们知道socket是只是网络和文件系统关联的接口抽象,没有网络的相关信息,从socket的数据结构容易看出,所以还有另一个网络抽象的重要的数据结构sock

因此所以肯定有一个创建sock的函数,这个函数就是在sock_alloc返回到sock_Create中调用的

Sock_create:(){

………

 

if ((i = net_families[family]->create(sock, protocol)) < 0)

       {

              sock_release(sock);

              goto out;

       }

……….

……….

}

调用具体family(ip,ipx等网络层协议)create函数,net_families[]数组的元素代表一种网络层协议(ip,ipx)等的相关数据及操作,create函数就是其中一个操作。

在这里是调用inet_create,inet_create创建sock,并根据具体协议初始化它。

Sys_socketcall->sys_socket->sock_create()->inet_create

static int inet_create(struct socket *sock, int protocol)

{

       struct sock *sk;

    struct list_head *p;

    struct inet_protosw *answer;

sock->state = SS_UNCONNECTED;

    // sk_alloc实现sock结构分配

       sk = sk_alloc(PF_INET, GFP_KERNEL, 1);

//,然后初始化sock结构sk

list_for_each(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;

       }

       br_read_unlock_bh(BR_NETPROTO_LOCK);

 

       if (!answer)

              goto free_and_badtype;

       if (answer->capability > 0 && !capable(answer->capability))

              goto free_and_badperm;

       if (!protocol)

              goto free_and_noproto;

 

       sock->ops = answer->ops;

       sk->prot = answer->prot;

}

上面inetswinet_protosw数据结构数组,是很重要的数据结构,提供了具体传输层的一些函数集,net_initinetsw_array赋值的。

Inet_init()

{

/* Register the socket-side information for inet_create. */

       for(r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)

              INIT_LIST_HEAD(r);

 

       for(q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)

              inet_register_protosw(q);

..........

}

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_dgram_ops,

               capability:  CAP_NET_RAW,

               no_check:    UDP_CSUM_DEFAULT,

               flags:       INET_PROTOSW_REUSE,

       }

};

至此数据初始化完成了,然后就调用具体传输层协议的初始化函数。

总结一下,整个创建过程创建了三个重要的数据结构,inodesocketsock

他们的关系图如下:

 

整个创建过程主要函数调用层次关系如下:

 

 Sock_create()                          //创建socket

->alloc_sock()             //创建初始的socket

           >get_empty_inode//获取一个Inode-

>socket_look_up()//填充具体inodesocket并初始化

            ->inet_create()         //完善socket结构体内容,如添加sock结构。

->alloc_sk    // 创建sock结构,并初始化socket->ops=inetsw[](具体// 协议的函数),sock->proto

                                   ->tcp_init

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值