Linux套接字与虚拟文件系统(1):初始化和创建 http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html
来源:互联网 发布:勇士vs马刺数据统计 编辑:程序博客网 时间:2024/06/06 09:36
Linux套接字与虚拟文件系统(1):初始化和创建
引言在Unix的世界里,万物皆文件,通过虚拟文件系统VFS,程序可以用标准的Unix系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作。对于网络套接字socket也是如此,除了专属的Berkeley Sockets API,还支持一些标准的文件IO系统调用如read(v)、write(v)和close等。那么为什么socket也支持文件IO系统调用呢?在Linux上,这是通过套接口伪文件系统sockfs来实现的,因为sockfs实现了VFS中的4种主要对象:超级块super block、索引节点inode、目录项对象dentry和文件对象file,当执行文件IO系统调用时,VFS就将请求转发给sockfs,而sockfs就调用特定的协议实现,层次结构如下图:
本文以linux 2.6.34实现为基础,本篇阐述初始化和Socket创建两部分的实现,下篇阐述Socket操作和销毁两部分的实现。
初始化
在内核引导时初始化网络子系统,进而调用sock_init,该函数主要步骤如下:创建inode缓存,注册和装载sockfs,定义在net/socket.c中。
1static int __init sock_init(void)
2{
3
4 init_inodecache();
5 register_filesystem(&sock_fs_type);
6 sock_mnt = kern_mount(&sock_fs_type);
7
8}
2{
3
4 init_inodecache();
5 register_filesystem(&sock_fs_type);
6 sock_mnt = kern_mount(&sock_fs_type);
7
8}
创建inode缓存
init_inodecache为socket_alloc对象创建SLAB缓存,名称为sock_inode_cachep,socket_alloc定义在include/net/sock.h中。
1struct socket_alloc {
2 struct socket socket;
3 struct inode vfs_inode;
4};
2 struct socket socket;
3 struct inode vfs_inode;
4};
socket_alloc由socket和inode结构2部分组成,这样就方便了在套接字与inode对象间双向定位。
注册sockfs
调用VFS的函数register_filesystem实现注册,sock_fs_type定义在net/socket.c中。
注册sockfs
调用VFS的函数register_filesystem实现注册,sock_fs_type定义在net/socket.c中。
1static struct file_system_type sock_fs_type = {
2 .name = "sockfs",
3 .get_sb = sockfs_get_sb,
4 .kill_sb = kill_anon_super,
5};
2 .name = "sockfs",
3 .get_sb = sockfs_get_sb,
4 .kill_sb = kill_anon_super,
5};
1static int sockfs_get_sb(struct file_system_type *fs_type,int flags, const char *dev_name, void *data,struct vfsmount *mnt)
2{
3 return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, mnt);
4}
2{
3 return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, mnt);
4}
sockfs_ops定义在net/socket.c中。
1static const struct super_operations sockfs_ops = {
2 .alloc_inode = sock_alloc_inode,
3 .destroy_inode = sock_destroy_inode,
4 .statfs = simple_statfs,
5};
2 .alloc_inode = sock_alloc_inode,
3 .destroy_inode = sock_destroy_inode,
4 .statfs = simple_statfs,
5};
装载sockfs
由kern_mount函数实现装载一个伪文件系统(当然,它没有装载点),返回一个static vfsmount对象sock_mnt。
经过以上步骤后,所创建的VFS对象关系如下图:
对于根目录项,不用进行路径转换,因此dentry的d_op为空(未画出);对于伪文件系统,操作索引对象没有意义,所以inode的i_op为空(未画出)。
Socket创建
系统调用socket、accept和socketpair是用户空间创建socket的几种方法,其核心调用链如下图:
从上图可知共同的核心就3个过程:先构造inode,再构造对应的file,最后安装file到当前进程中(即关联映射到一个未用的文件描述符),下面就这3个过程进行详细说明。
构造inode
由sock_alloc函数实现,定义在net/socket.c中。
1static struct socket *sock_alloc(void)
2{
3 struct inode *inode;
4 struct socket *sock;
5
6 inode = new_inode(sock_mnt->mnt_sb);
7
8 sock = SOCKET_I(inode);
9
10 inode->i_mode = S_IFSOCK | S_IRWXUGO;
11 inode->i_uid = current_fsuid();
12 inode->i_gid = current_fsgid();
13
14 return sock;
15}
2{
3 struct inode *inode;
4 struct socket *sock;
5
6 inode = new_inode(sock_mnt->mnt_sb);
7
8 sock = SOCKET_I(inode);
9
10 inode->i_mode = S_IFSOCK | S_IRWXUGO;
11 inode->i_uid = current_fsuid();
12 inode->i_gid = current_fsgid();
13
14 return sock;
15}
构造file
有了inode对象后,接下来就要构造对应的file对象了,由sock_alloc_file实现,定义在net/socket.c中。
1static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
2{
3 struct qstr name = { .name = "" };
4 struct path path;
5 struct file *file;
6 int fd;
7
8 fd = get_unused_fd_flags(flags);
9
10 path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
11
12 path.mnt = mntget(sock_mnt);
13
14 path.dentry->d_op = &sockfs_dentry_operations;
15 d_instantiate(path.dentry, SOCK_INODE(sock));
16 SOCK_INODE(sock)->i_fop = &socket_file_ops;
17
18 file = alloc_file(&path, FMODE_READ | FMODE_WRITE, &socket_file_ops);
19
20 sock->file = file;
21 file->f_flags = O_RDWR | (flags & O_NONBLOCK);
22 file->f_pos = 0;
23 file->private_data = sock;
24
25 *f = file;
26 return fd;
27}
2{
3 struct qstr name = { .name = "" };
4 struct path path;
5 struct file *file;
6 int fd;
7
8 fd = get_unused_fd_flags(flags);
9
10 path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
11
12 path.mnt = mntget(sock_mnt);
13
14 path.dentry->d_op = &sockfs_dentry_operations;
15 d_instantiate(path.dentry, SOCK_INODE(sock));
16 SOCK_INODE(sock)->i_fop = &socket_file_ops;
17
18 file = alloc_file(&path, FMODE_READ | FMODE_WRITE, &socket_file_ops);
19
20 sock->file = file;
21 file->f_flags = O_RDWR | (flags & O_NONBLOCK);
22 file->f_pos = 0;
23 file->private_data = sock;
24
25 *f = file;
26 return fd;
27}
1)得到空闲的文件描述符fd,实际上就是fd数组的索引,准备作为返回值。
2)先初始化路径path:其目录项的父目录项为超级块对应的根目录,名称为空,操作对象为sockfs_dentry_operations,对应的索引节点对象为sock套接字关联的索引节点对象,即SOCK_INODE(sock);装载点为sock_mnt。
sockfs_dentry_operations定义在net/socket.c中。
1static const struct dentry_operations sockfs_dentry_operations = {
2 .d_dname = sockfs_dname,
3};
2 .d_dname = sockfs_dname,
3};
3)设置索引节点的文件操作对象为socket_file_ops,定义在net/socket.c中。
1static const struct file_operations socket_file_ops = {
2
3 .aio_read = sock_aio_read,
4 .aio_write = sock_aio_write,
5
6 .open = sock_no_open, /* special open code to disallow open via /proc */
7 .release = sock_close,
8
9};
2
3 .aio_read = sock_aio_read,
4 .aio_write = sock_aio_write,
5
6 .open = sock_no_open, /* special open code to disallow open via /proc */
7 .release = sock_close,
8
9};
5)建立file与socket的一一映射关系。
安装file
由fd_install实现,定义在fs/open.c中。
1void fd_install(unsigned int fd, struct file *file)
2{
3 struct files_struct *files = current->files;
4 struct fdtable *fdt;
5 spin_lock(&files->file_lock);
6 fdt = files_fdtable(files);
7 BUG_ON(fdt->fd[fd] != NULL);
8 rcu_assign_pointer(fdt->fd[fd], file);
9 spin_unlock(&files->file_lock);
10}
2{
3 struct files_struct *files = current->files;
4 struct fdtable *fdt;
5 spin_lock(&files->file_lock);
6 fdt = files_fdtable(files);
7 BUG_ON(fdt->fd[fd] != NULL);
8 rcu_assign_pointer(fdt->fd[fd], file);
9 spin_unlock(&files->file_lock);
10}
经过以上过程后,所创建的VFS对象关系图如下
fd为file*数组的索引而不是成员字段;vfsmount与初始化之VFS对象关系图中的vfsmount是同一个对象,即sock_mnt;对于伪文件系统,操作索引对象没有意义,所以inode的i_op为空(未画出)。
posted on 2015-05-03 16:31 春秋十二月 阅读(1854) 评论(0) 编辑 收藏 引用 所属分类: Network
0 0
- Linux套接字与虚拟文件系统(1):初始化和创建 http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html
- Linux套接字与虚拟文件系统(1):初始化和创建 http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html
- Linux 硬限制和软限制 http://www.cppblog.com/API/archive/2012/03/19/168289.html
- 学好算法 (摘自:http://www.cppblog.com/w2001/archive/2007/03/23/20396.html)
- 模版详解(模版与宏) 转自:http://www.cppblog.com/zmllegtui/archive/2008/10/28/65316.html
- tinyxml使用笔记与总结 http://www.cppblog.com/elva/archive/2008/04/24/47907.html
- 子类化和超子类化http://www.cppblog.com/wangjia184/archive/2008/03/27/45520.html
- 如何检查C++中的内存泄漏 (原文地址:http://www.cppblog.com/Lyt/archive/2009/03/22/77517.html)
- 容斥原理(转载http://www.cppblog.com/vici/archive/2011/09/05/155103.html)
- http://www.cppblog.com/oosky/archive/2006/01/03/2365.html
- LIB和DLL的区别、建立及使用http://www.cppblog.com/amazon/archive/2009/09/04/95318.html
- 二分查找学习札记转自http://www.cppblog.com/converse/archive/2009/10/05/97905.html
- Bellman-Ford算法(转自http://www.cppblog.com/infinity/archive/2008/11/11/66621.html)
- VC调试总结 zz http://www.cppblog.com/kevinlynx/archive/2008/04/24/47998.html 博客。
- VC调试总结 zz http://www.cppblog.com/kevinlynx/archive/2008/04/24/47998.html 博客。
- http://www.cppblog.com/twzheng/archive/2008/07/07/55563.html
- NLP常用工具 from:http://www.cppblog.com/baby-fly/archive/2010/10/08/129003.html
- http://www.cppblog.com/lf426/archive/2010/06/25/118739.html
- 树的重心 树形DP SGU 134
- 机房收费系统之优化篇
- python若干小函数的使用
- SDUTOJ3252---Lowest Unique Price
- 20150902 Java学习笔记-构造方法,关键字,封装性
- Linux套接字与虚拟文件系统(1):初始化和创建 http://www.cppblog.com/qinqing1984/archive/2015/05/03/210521.html
- android-------采用AIDL调用远程服务
- CIDR与NAT
- hdu 5417 Victor and Machine
- 【codechef】Singal Pipes(DFS求期望)
- 初始化和清除
- iOS 9.0 随机数
- POJ 2125 Destroying The Graph(二分图最小点权覆盖)
- HDU 4916(Count on the path-树上除链上的节点外最小值[强制在线])