Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145829
  • 博文数量: 40
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 410
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-11 09:11
文章分类

全部博文(40)

文章存档

2020年(1)

2017年(36)

2014年(3)

我的朋友

分类: LINUX

2014-11-30 00:11:30

[前言]

一直想好好研究linux的网络实现,又不知从何入手,总是片面的学习,形不成体系。最近发现秦健老师的《追踪Linux TCP/IP 代码运行》,觉得是个不错的入口点,于是决定借此一来整合一下自己零碎的知识,二来希望对节后的工作有些帮助,何乐而不为。本文仅仅是介绍从调用socket函数到成功返回一个socket文件描述符之间所涉及到的重要函数以及其调用关系、代码位置等,该过程涉及的重要数据结构以及相关知识会有专门的介绍。

[linux内核版本:3.10.25]

[
] GLIBC封装的库函数到系统调用

我们平常在网络编程中调用的socket()函数,实为GLIBC封装的库函数,该库函数实际功能采用汇编语言实现,最后通过0x80号软中断陷入内核,调用真正的系统调用程序。

|>> socket() :

|创建一个socket套接字

|int socket(int domain, int type, int protocol);

|glibc-2.20/sysdeps/unix/sysv/linux/i386/socket.S[43]

---|>> int $0x80 : 

---|0x80号软中断用来陷入内核,然后调用系统调用的总入口system_call

---|---|>> system_call() :

---|---|系统调用的总入口,完全用汇编语言实现

---|---|asmlinkage int system_call(void);

---|---|linux-3.10.25/arch/x86/kernel/entry_64.S[608]

---|---|---|>> sys_socketcall() : 

---|---|---|内核提供给socket通信的总入口

---|---|---|asmlinkage long sys_socketcall(int call, unsigned long __user *args);

---|---|---|linux-3.10.25/net/socket.c[2456]

点击(此处)折叠或打开

  1. SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
  2. {
  3.     ......
  4.     /* copy_from_user should be SMP safe. */
  5.     if (copy_from_user(a, args, len))
  6.         return -EFAULT;
  7.     ......
  8.     switch (call) {
  9.     case SYS_SOCKET:
  10.         err = sys_socket(a0, a1, a[2]);
  11.         break;
  12.     case SYS_BIND:
  13.         err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
  14.         break;
  15.     case SYS_CONNECT:
  16.         err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
  17.         break;
  18.     case SYS_LISTEN:
  19.         err = sys_listen(a0, a1);
  20.         break;
  21.     case SYS_ACCEPT:
  22.         err = sys_accept4(a0, (struct sockaddr __user *)a1,
  23.                  (int __user *)a[2], 0);
  24.         break;


[
] 调用sys_socket创建socketsock结构体

在Linux-3.10.25socket系列函数(sys_xxx)在内核源码中都是用DEFINEX宏来定义,关于DEFINEX的定义请查看linux-3.10.25/include/linux/syscalls.h[170],至于为什么这样做不是我们关心的重点,使用这些宏转换后,这些函数的真面目与2.6系列内核中的定义没有什么不同,或者我们也可以直接查看这些函数在头文件中的声明来确定这些函数的原型。

|>>sys_socket() 

|asmlinkage long sys_socket(int family, int type, int protocol);

|SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)

|linux-3.10.25/net/socket.c[1361]

---|>> sock_create() :

---|直接调用__scok_create()函数执行创建任务

---| int sock_create(int family, int type, int protocol, struct socket **res)

---|linux-3.10.25/net/socket.c[1349]                                

---|---|>>  __sock_create() 

---|---|创建socketsock结构体

---|---|int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern)

---|---| linux-3.10.25/net/socket.c[1236]

---|---|---|>> sock_alloc() :

---|---|---|创建socket结构体 

---|---|---|static struct socket *sock_alloc(void)

---|---|---|linux-3.10.25/net/socket.c[531]

---|---|---|>>inet_create() :

---|---|---|创建scok结构 __scok_create函数中的1311行被调用

---|---|---|static int inet_create(struct net *net, struct socket *sock, int protocol, int kern) 

---|---|---|linux-3.10.25/net/ipv4/af_inet.c[275]

__sock_create()函数中linux系统创建了两个重要的数据结构,socketsock结构体。Sock结构体根据使用的具体协议挂入socket结构体中,同时sock结构体中又包含了指向sk_buff结构的指针。sk_buff这个结构相信大家并不陌生,每个协议都是用该结构体来封装、运载数据包,也就说每一个数据包都用一个sk_buff结构体来表示。


[
] 调用sock_alloc()函数创建socket结构体

|>> sock_alloc() :

|创建socket结构体

|static struct socket *sock_alloc(void)

|linux-3.10.25/net/socket.c[531]

---|>> new_inode_pseudo() 

---|给指定的超级块结构申请一个inode

---|struct inode *new_inode_pseudo(struct super_block *sb)

---| linux-3.10.25/fs/inode.c[904]

---|---|>> alloc_inode() 

---|---|给指定的超级块结构申请一个inode

---|---|static struct inode *alloc_inode(struct super_block *sb)

---|---|linux-3.10.25/fs/inode.c[202]

---|---|---|>>sock_alloc_inode() :

---|---|---|给指定的超级块结构申请一个inode,在alloc_inode函数中207行被调用

---|---|---|static struct inode *sock_alloc_inode(struct super_block *sb)

---|---|---|linux-3.10.25/net/socket.c[241]

点击(此处)折叠或打开

  1. static struct inode *alloc_inode(struct super_block *sb)
  2. {
  3.     struct inode *inode;

  4.     if (sb->s_op->alloc_inode)
  5.         /* 我们在这里调用sock_alloc_inode函数来创建socket和inode */
  6.         inode = sb->s_op->alloc_inode(sb);
  7.     else
  8.         inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);

点击(此处)折叠或打开

  1. /* linux-3.10.25/net/socket.c[299] */
  2. static const struct super_operations sockfs_ops = {
  3.     .alloc_inode    = sock_alloc_inode,
  4.     .destroy_inode    = sock_destroy_inode,
  5.     .statfs        = simple_statfs,
  6. }

点击(此处)折叠或打开

  1. /* linux-3.10.25/net/socket.c[241] */
  2. static struct inode *sock_alloc_inode(struct super_block *sb)
  3. {
  4.     struct socket_alloc *ei;
  5.     struct socket_wq *wq;

  6.     ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
  7.     if (!ei)
  8.         return NULL;
  9.     wq = kmalloc(sizeof(*wq), GFP_KERNEL);
  10.     if (!wq) {
  11.         kmem_cache_free(sock_inode_cachep, ei);
  12.         return NULL;
  13.     }
  14.     init_waitqueue_head(&wq->wait);
  15.     wq->fasync_list = NULL;
  16.     RCU_INIT_POINTER(ei->socket.wq, wq);

  17.     ei->socket.state = SS_UNCONNECTED;
  18.     ei->socket.flags = 0;
  19.     ei->socket.ops = NULL;
  20.     ei->socket.sk = NULL;
  21.     ei->socket.file = NULL;

  22.     return &ei->vfs_inode;
  23. }

[] 调用inet_create()函数创建sock结构体

|>> inet_create() :

|创建并设置sock结构体,在__sock_create函数中1311行被调用

| static int inet_create(struct net *net, struct socket *sock, int protocol, int kern)

| linux-3.10.25/net/ipv4/af_inet.c[275]

---|>>sk_alloc() :

---|创建并初始化sock结构体

---|struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot)

---| linux-3.10.25/core/scok.c[1314]

---|---|>>sk_prot_alloc() :

---|---|创建socket结构体

---|---|static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, int family)

---|---|linux-3.10.25/core/scok.c[1225]

点击(此处)折叠或打开

  1. /* 在这里我们创建sock结构体 */
  2.     err = pf->create(net, sock, protocol, kern);
  3.     if (err < 0)
  4.         goto out_module_put;

点击(此处)折叠或打开

  1. /* linux-3.10.25/net/ipv4/af_inet.c[1019] */
  2. static const struct net_proto_family inet_family_ops = {
  3.     .family = PF_INET,
  4.     .create = inet_create,
  5.     .owner    = THIS_MODULE,
  6. };

点击(此处)折叠或打开

  1. /* linux-3.10.25/net/ipv4/af_inet.c[275] */
  2. static int inet_create(struct net *net, struct socket *sock, int protocol,
  3.          int kern)
  4. {
  5.     struct sock *sk;

点击(此处)折叠或打开

  1. struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
  2.          struct proto *prot)
  3. {
  4.     struct sock *sk;

  5.     sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);
  6.     if (sk) {
  7.         /* 如果sock结构体分配成功那么将在该函数做一些初始化工作 */
  8.         sk->sk_family = family;
  9.         /*
  10.          * See comment in struct sock definition to understand
  11.          * why we need sk_prot_creator -acme
  12.          */
  13.         sk->sk_prot = sk->sk_prot_creator = prot;
  14.         sock_lock_init(sk);
  15.         sock_net_set(sk, get_net(net));
  16.         atomic_set(&sk->sk_wmem_alloc, 1);

  17.         sock_update_classid(sk);
  18.         sock_update_netprioidx(sk);
  19.     }

  20.     return sk;

阅读(1442) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:使用python解析xml之ElementTree

给主人留下些什么吧!~~