Linux内核分析 - 网络[十二]:UDP模块 - socket
副标题[/!--empirenews.page--] 内核版本:2.6.34 这部分内容在于说明socket创建后如何被内核协议栈访问到,只关注两个问题:sock何时插入内核 表的,sock如何被内核访问的。对于核心的sock的插入、查找函数都给出了流程图。 sock如何插入内核表 socket创建后就可以用来与外部网络通信,用户可以通过文件描述符fd来找到要操作的socket,内核则通过查表 来找到要操作的socket。这意味着socket创建时会在文件系统中生成相应项,同时还会插入到存储socket的表中,方便用户和内 核通过两种方式进行访问。 以创建如下udp socket为例,这里的创建仅仅指定socket的协议簇是 AF_INET,类型是SOCK_DGRAM,协议是0,此时创建了socket,相应文件描述符,但仍缺少其它信息,此时socket并未插入到内核 表中,还是处于游离态,除了用户通过fd操作,内核是看不到的socket的。 fd = socket(AF_INET, SOCK_DGRAM, 0); 根据作为的角色(服务器或客户端)不同,接下来执行的动作也不相同。这两句分条时服务 器和客户端与外部通信的第一句,执行后,与外部连接建立,socket的插入内核表也是由这两句触发的。 服务器端udp socket bind(fd, &serveraddr, sizeof(serveraddr)); 客户端 udp socket 下面来看下创建socket的具体动作,只涉及与socket存储相关的代码,这些系统调用的其它方面以后再具体 分析。 sys_socket() 创建socket,映射文件描述符fd retval = sock_create(family, type, protocol, &sock); retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); 在内核中,有struct socket,也就是通常 所说的socket,表示网络的接口,还有struct sock,则是AF_INET域的接口。一般struct socket成员叫sock,struct sock成员 叫sk,在代码中不要混淆。 sock_create() -- > __sock_create() 最终执行__sock_create()来创建,注意__sock_create()最后一个参数是0,表示是由用户创建的;如果是1,则表示是由 内核创建的。 分配socket并设置sock->type为SOCK_DGRAM。 sock = sock_alloc(); sock->type = type; 从net_families中取得AF_INET(也即PF_INET)协议族的参数,net_families数组存储不同协 议族的参数,像AF_INET协议族是在加载IP模块时注册的,inet_init() -> sock_register(&inet_family_ops), sock_register()就是将参数加入到net_families数组中,inet_family_ops定义如下: pf = rcu_dereference(net_families[family]); static const struct net_proto_family inet_family_ops = { .family = PF_INET, .create = inet_create, .owner = THIS_MODULE, }; 最后调用相应协议簇的创建方法,这里的pf->create()就是inet_create(),它创建INET域的结构sock。 err = pf->create(net, sock, protocol, kern); 从 __sock_create()代码看到创建包含两步:sock_alloc()和pf->create()。sock_alloc()分配了sock内存空间并初始化inode ;pf->create()初始化了sk。 sock_alloc() 分配空间,通过new_inode()分配了节点( 包括socket),然后通过SOCKET_I宏获得sock,实际上inode和sock是在new_inode()中一起分配的,结构体叫作sock_alloc。 inode = new_inode(sock_mnt->mnt_sb); sock = SOCKET_I(inode); 设置inode的参数,并返回sock。 inode- >i_mode = S_IFSOCK | S_IRWXUGO; inode->i_uid = current_fsuid(); inode->i_gid = current_fsgid(); return sock; 继续往下看具体的创建过程:new_inode(),在分配后,会设置i_ino和i_state的值。 struct inode *new_inode(struct super_block *sb) { …… inode = alloc_inode(sb); if (inode) { spin_lock(&inode_lock); __inode_add_to_lists(sb, NULL, inode); inode->i_ino = ++last_ino; inode->i_state = 0; spin_unlock(&inode_lock); } return inode; } 其中的alloc_inode() -> sb->s_op->alloc_inode(),sb是sock_mnt->mnt_sb,所以 alloc_inode()指向的是sockfs的操作函数sock_alloc_inode。 static const struct super_operations sockfs_ops = { .alloc_inode = sock_alloc_inode, .destroy_inode =sock_destroy_inode, .statfs = simple_statfs, }; sock_alloc_inode()中通过kmem_cache_alloc()分配了struct socket_alloc结构体大小的空间,而struct socket_alloc结构体定义如下,但只返回了inode,实际上socket和inode都已经分配了空间,在之后就可以通过container_of取 到socket。 static struct inode *sock_alloc_inode(struct super_block *sb) { struct socket_alloc *ei; ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); ….. return &ei->vfs_inode; } struct socket_alloc { struct socket socket; struct inode vfs_inode; }; inet_create() 从inetsw中根据类型、协议查找相应的socket interface。 list_for_each_entry_rcu(answer, &inetsw[sock->type], list) { …… if (IPPROTO_IP == answer->protocol) break; …… } (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |