Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1504241
  • 博文数量: 228
  • 博客积分: 1698
  • 博客等级: 上尉
  • 技术积分: 3241
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-24 21:49
个人简介

Linux

文章分类

全部博文(228)

文章存档

2017年(1)

2016年(43)

2015年(102)

2014年(44)

2013年(5)

2012年(30)

2011年(3)

分类: LINUX

2014-08-14 00:09:09

为了建立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函数对应了内核的如下接口

点击(此处)折叠或打开

  1. SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
  2. {
  3.     ......
  4.     retval = sock_create(family, type, protocol, &sock);
  5.     if (retval < 0)
  6.         goto out;

  7.     retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
  8.     if (retval < 0)
  9.         goto out_release;
  10.     ......
  11. }
这里只关注sock_create和sock_map_fd函数的实现,其中sock_create只是对__sock_create函数的简单封装

点击(此处)折叠或打开

  1. int sock_create(int family, int type, int protocol, struct socket **res)
  2. {
  3.     return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
  4. }
  5. static int __sock_create(struct net *net, int family, int type, int protocol,
  6.              struct socket **res, int kern)
  7. {
  8.     ......
  9.     sock = sock_alloc();
  10.     if (!sock) {
  11.         if (net_ratelimit())
  12.             printk(KERN_WARNING "socket: no more sockets\n");
  13.         return -ENFILE;    /* Not exactly a match, but its the
  14.                  closest posix thing */
  15.     }

  16.     sock->type = type;

  17.     err = pf->create(net, sock, protocol);
  18.     if (err < 0)
  19.         goto out_module_put;
  20.     ......
  21. }
其中sock_alloc用于申请socket结构

点击(此处)折叠或打开

  1. static struct socket *sock_alloc(void)
  2. {
  3.     struct inode *inode;
  4.     struct socket *sock;

  5.     inode = new_inode(sock_mnt->mnt_sb);
  6.     if (!inode)
  7.         return NULL;

  8.     sock = SOCKET_I(inode);

  9.     kmemcheck_annotate_bitfield(sock, type);
  10.     inode->i_mode = S_IFSOCK | S_IRWXUGO;
  11.     inode->i_uid = current_fsuid();
  12.     inode->i_gid = current_fsgid();

  13.     percpu_add(sockets_in_use, 1);
  14.     return sock;
  15. }
sock_mnt是在socket初始化向系统挂载sock_fs时保存的vfsmount结构,其mnt_sb指向了该文件系统对应的超级块。new_inode函数用于从sock_fs文件系统中申请一个节点

点击(此处)折叠或打开

  1. struct inode *new_inode(struct super_block *sb)
  2. {
  3.     /*
  4.      * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
  5.      * error if st_ino won't fit in target struct field. Use 32bit counter
  6.      * here to attempt to avoid that.
  7.      */
  8.     static unsigned int last_ino;
  9.     struct inode *inode;

  10.     spin_lock_prefetch(&inode_lock);

  11.     inode = alloc_inode(sb);
  12.     .......


  13. static struct inode *alloc_inode(struct super_block *sb)
  14. {
  15.     struct inode *inode;

  16.     if (sb->s_op->alloc_inode)
  17.         inode = sb->s_op->alloc_inode(sb);
  18.     else
  19.         inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
  20.     .......
申请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的实现

点击(此处)折叠或打开

  1. static inline struct socket *SOCKET_I(struct inode *inode)
  2. {
  3.     return &container_of(inode, struct socket_alloc, vfs_inode)->socket;
  4. }
通过inode来获取socket的地址,实际上只做了一下地址的偏移,这样一次申请inode和socket就都申请到了,通过inode和socket的地址都可以很容易获取另外一个的地址。

到目前为止申请socket的过程结束了,我们回到__sock_create函数中,继续往下分析。这个函数先调用了sock_alloc申请socket(前面刚分析完),然后根据API传入的family信息确定是那个协议簇,然后调用协议簇对应的create函数:err = pf->create(net, sock, protocol)

这里不同的协议簇走的流程开始不一样了,我们从下一篇再开始分析。

阅读(1762) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~