加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[十二]:UDP模块 - socket

发布时间:2016-05-28 22:15:56 所属栏目:Linux 来源:网络整理
导读:内核版本:2.6.34 这部分内容在于说明socket创建后如何被内核协议栈访问到,只关注两个问题:sock何时插入内核 表的,sock如何被内核访问的。对于核心的sock的
副标题[/!--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;     
 ……     
}

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读