为了建立Socket,程序可以调用Socket函数,函数返回一个文件描述符,原型为:
int socket(int domain, int type, int protocol);
domain:指定协议簇,常见的有AF_IENT, AF_INET6, AF_UNIX/AF_LOCAL, AF_NETLINK等
type:指定类型,常见的有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等
protocol:指定传输协议,如TCP/UDP等,不同协议簇都对应了默认的协议,可以填充0使用默认值
socket函数对应了内核的如下接口
-
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
-
{
-
......
-
retval = sock_create(family, type, protocol, &sock);
-
if (retval < 0)
-
goto out;
-
-
retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
-
if (retval < 0)
-
goto out_release;
-
......
-
}
这里只关注sock_create和sock_map_fd函数的实现,其中sock_create只是对__sock_create函数的简单封装
-
int sock_create(int family, int type, int protocol, struct socket **res)
-
{
-
return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
-
}
-
static int __sock_create(struct net *net, int family, int type, int protocol,
-
struct socket **res, int kern)
-
{
-
......
-
sock = sock_alloc();
-
if (!sock) {
-
if (net_ratelimit())
-
printk(KERN_WARNING "socket: no more sockets\n");
-
return -ENFILE; /* Not exactly a match, but its the
-
closest posix thing */
-
}
-
-
sock->type = type;
-
-
err = pf->create(net, sock, protocol);
-
if (err < 0)
-
goto out_module_put;
-
......
-
}
其中sock_alloc用于申请socket结构
-
static struct socket *sock_alloc(void)
-
{
-
struct inode *inode;
-
struct socket *sock;
-
-
inode = new_inode(sock_mnt->mnt_sb);
-
if (!inode)
-
return NULL;
-
-
sock = SOCKET_I(inode);
-
-
kmemcheck_annotate_bitfield(sock, type);
-
inode->i_mode = S_IFSOCK | S_IRWXUGO;
-
inode->i_uid = current_fsuid();
-
inode->i_gid = current_fsgid();
-
-
percpu_add(sockets_in_use, 1);
-
return sock;
-
}
sock_mnt是在socket初始化向系统挂载sock_fs时保存的vfsmount结构,其mnt_sb指向了该文件系统对应的超级块。new_inode函数用于从sock_fs文件系统中申请一个节点
-
struct inode *new_inode(struct super_block *sb)
-
{
-
/*
-
* On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
-
* error if st_ino won't fit in target struct field. Use 32bit counter
-
* here to attempt to avoid that.
-
*/
-
static unsigned int last_ino;
-
struct inode *inode;
-
-
spin_lock_prefetch(&inode_lock);
-
-
inode = alloc_inode(sb);
-
.......
-
-
-
static struct inode *alloc_inode(struct super_block *sb)
-
{
-
struct inode *inode;
-
-
if (sb->s_op->alloc_inode)
-
inode = sb->s_op->alloc_inode(sb);
-
else
-
inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
-
.......
申请inode的过程实际上最后对应了sb->s_op->alloc_inode,也就是对应了第一篇文档中介绍到的sock_alloc_inode函数,这个函数实际上申请的是一个socket_alloc结构,而socket_alloc结构同时包含了socket和vfs_inode,函数返回时返回了vfs_inode的地址,这样在申请inode的同时实际上把socket也申请出来了。
现在我们回头看上面sock_alloc函数的实现,在调用new_inode之后,使用了sock = SOCKET_I(inode)来获取socket,我们看一下SOCKET_I的实现
-
static inline struct socket *SOCKET_I(struct inode *inode)
-
{
-
return &container_of(inode, struct socket_alloc, vfs_inode)->socket;
-
}
通过inode来获取socket的地址,实际上只做了一下地址的偏移,这样一次申请inode和socket就都申请到了,通过inode和socket的地址都可以很容易获取另外一个的地址。
到目前为止申请socket的过程结束了,我们回到__sock_create函数中,继续往下分析。这个函数先调用了sock_alloc申请socket(前面刚分析完),然后根据API传入的family信息确定是那个协议簇,然后调用协议簇对应的create函数:err = pf->create(net, sock, protocol)
这里不同的协议簇走的流程开始不一样了,我们从下一篇再开始分析。
阅读(1762) | 评论(0) | 转发(0) |