Linux内核--网络栈实现分析(八)--应用层发送数据(下)

时间:2023-12-30 17:12:44

本文分析基于Linux Kernel 1.2.13

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7547826

更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

下面是发送数据的流程:

Linux内核--网络栈实现分析(八)--应用层发送数据(下)

应用层发送数据包的入口函数是BSD socket层的sock_write()函数,在分析该函数之前,先分析下socket的创建,系统调用sys_socket()对应的BSD socket层函数为sock_socket()

sock_socket()函数

  1. /*
  2. *  Perform the socket system call. we locate the appropriate
  3. *  family, then create a fresh socket.
  4. */
  5. static int sock_socket(int family, int type, int protocol)
  6. {
  7. int i, fd;
  8. struct socket *sock;
  9. struct proto_ops *ops;
  10. /* Locate the correct protocol family. */
  11. for (i = 0; i < NPROTO; ++i) //查找对应的协议族
  12. {
  13. if (pops[i] == NULL) continue;
  14. if (pops[i]->family == family)
  15. break;
  16. }
  17. if (i == NPROTO) //查找未果,返回错误
  18. {
  19. return -EINVAL;
  20. }
  21. ops = pops[i];//指针指向该协议族的原型操作函数集
  22. /*
  23. *  Check that this is a type that we know how to manipulate and
  24. *  the protocol makes sense here. The family can still reject the
  25. *  protocol later.
  26. */
  27. if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
  28. type != SOCK_SEQPACKET && type != SOCK_RAW &&
  29. type != SOCK_PACKET) || protocol < 0)
  30. return(-EINVAL);
  31. /*
  32. *  Allocate the socket and allow the family to set things up. if
  33. *  the protocol is 0, the family is instructed to select an appropriate
  34. *  default.
  35. */
  36. if (!(sock = sock_alloc())) //获取一个socket,已经完成了socket部分初始化设置
  37. {
  38. printk("NET: sock_socket: no more sockets\n");
  39. return(-ENOSR); /* Was: EAGAIN, but we are out of
  40. system resources! */
  41. }
  42. sock->type = type;
  43. sock->ops = ops;
  44. if ((i = sock->ops->create(sock, protocol)) < 0) //调用INET层函数,inet_create()函数,创建inet层的socket,即sock结构
  45. {
  46. sock_release(sock);
  47. return(i);
  48. }
  49. if ((fd = get_fd(SOCK_INODE(sock))) < 0) //根据sock结构中的inode,分配文件描述符
  50. {
  51. sock_release(sock);
  52. return(-EINVAL);
  53. }
  54. return(fd);
  55. }

该函数的大体功能:

1、分配socket,sock结构,用于BSD和INET层的socket

2、分配inode和file结构,用于文件操作

3、返回文件操作描述符,用于应用程序的使用

其中初始化分配一个socket的方法如下:

  1. /*
  2. *  Allocate a socket.
  3. */
  4. struct socket *sock_alloc(void)
  5. {
  6. struct inode * inode;
  7. struct socket * sock;
  8. inode = get_empty_inode();//获一个空的文件结点
  9. if (!inode)
  10. return NULL;
  11. //文件结点相应字段赋值
  12. inode->i_mode = S_IFSOCK;
  13. inode->i_sock = 1;
  14. inode->i_uid = current->uid;
  15. inode->i_gid = current->gid;
  16. sock = &inode->u.socket_i;//给sicket结构指针赋值,可以看到inode和socket一一对应
  17. sock->state = SS_UNCONNECTED;
  18. sock->flags = 0;
  19. sock->ops = NULL;
  20. sock->data = NULL;
  21. sock->conn = NULL;
  22. sock->iconn = NULL;
  23. sock->next = NULL;
  24. sock->wait = &inode->i_wait;
  25. sock->inode = inode;     /* "backlink": we could use pointer arithmetic instead */
  26. sock->fasync_list = NULL;
  27. sockets_in_use++;
  28. return sock;
  29. }

执行完,然后调用INET层的inet_create()函数

  1. /*
  2. *  Create an inet socket.
  3. *
  4. *  FIXME: Gcc would generate much better code if we set the parameters
  5. *  up in in-memory structure order. Gcc68K even more so
  6. */
  7. //创建inet socket,即sock结构
  8. static int inet_create(struct socket *sock, int protocol)
  9. {
  10. struct sock *sk;
  11. struct proto *prot;
  12. int err;
  13. sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);//分配空间
  14. if (sk == NULL)
  15. return(-ENOBUFS);
  16. sk->num = 0;
  17. sk->reuse = 0;
  18. switch(sock->type)
  19. {
  20. case SOCK_STREAM:
  21. case SOCK_SEQPACKET:
  22. .................
  23. case SOCK_DGRAM:
  24. if (protocol && protocol != IPPROTO_UDP)
  25. {
  26. kfree_s((void *)sk, sizeof(*sk));
  27. return(-EPROTONOSUPPORT);
  28. }
  29. protocol = IPPROTO_UDP;
  30. sk->no_check = UDP_NO_CHECK;
  31. prot=&udp_prot;//原型指针指向UDP的原型定义
  32. break;
  33. case SOCK_RAW:
  34. .........................
  35. break;
  36. case SOCK_PACKET:
  37. ..........................
  38. break;
  39. default:
  40. kfree_s((void *)sk, sizeof(*sk));
  41. return(-ESOCKTNOSUPPORT);
  42. }
  43. sk->socket = sock;//可以看出sock和socket的对应关系
  44. .................
  45. sk->type = sock->type;
  46. sk->stamp.tv_sec=0;
  47. sk->protocol = protocol;
  48. sk->wmem_alloc = 0;
  49. sk->rmem_alloc = 0;
  50. sk->sndbuf = SK_WMEM_MAX;
  51. sk->rcvbuf = SK_RMEM_MAX;
  52. ......................................//sock的初始化
  53. /* this is how many unacked bytes we will accept for this socket.  */
  54. sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
  55. /* how many packets we should send before forcing an ack.
  56. if this is set to zero it is the same as sk->delay_acks = 0 */
  57. sk->max_ack_backlog = 0;
  58. sk->inuse = 0;
  59. sk->delay_acks = 0;
  60. skb_queue_head_init(&sk->write_queue);
  61. skb_queue_head_init(&sk->receive_queue);
  62. sk->mtu = 576;
  63. sk->prot = prot;
  64. sk->sleep = sock->wait;
  65. sk->daddr = 0;//远端地址
  66. sk->saddr = 0 /* ip_my_addr() */;//本地地址
  67. sk->err = 0;
  68. sk->next = NULL;
  69. sk->pair = NULL;
  70. sk->send_tail = NULL;//发送链表尾
  71. sk->send_head = NULL;//发送链表头
  72. ..............................
  73. skb_queue_head_init(&sk->back_log);//初始化双链表
  74. ..................................
  75. sk->ip_tos=0;
  76. sk->ip_ttl=64;
  77. ...................................
  78. if (sk->num) //本地端口号不空
  79. {
  80. /*
  81. * It assumes that any protocol which allows
  82. * the user to assign a number at socket
  83. * creation time automatically
  84. * shares.
  85. */
  86. put_sock(sk->num, sk);//根据端口号将sock结构加入sock表中
  87. sk->dummy_th.source = ntohs(sk->num);
  88. }
  89. if (sk->prot->init) //UDP的初始化函数为空
  90. {
  91. err = sk->prot->init(sk);
  92. if (err != 0)
  93. {
  94. destroy_sock(sk);
  95. return(err);
  96. }
  97. }
  98. return(0);
  99. }

返回文件描述的操作符

  1. /*
  2. *  Obtains the first available file descriptor and sets it up for use.
  3. */
  4. //根据文件inode指针创建文件结构,并返回文件操作的操作符,用于应用程序的使用
  5. static int get_fd(struct inode *inode)
  6. {
  7. int fd;
  8. struct file *file;
  9. /*
  10. *  Find a file descriptor suitable for return to the user.
  11. */
  12. file = get_empty_filp();
  13. if (!file)
  14. return(-1);
  15. for (fd = 0; fd < NR_OPEN; ++fd)
  16. if (!current->files->fd[fd])
  17. break;
  18. if (fd == NR_OPEN)
  19. {
  20. file->f_count = 0;
  21. return(-1);
  22. }
  23. FD_CLR(fd, &current->files->close_on_exec);
  24. current->files->fd[fd] = file;
  25. file->f_op = &socket_file_ops;
  26. file->f_mode = 3;
  27. file->f_flags = O_RDWR;
  28. file->f_count = 1;
  29. file->f_inode = inode;
  30. if (inode)
  31. inode->i_count++;
  32. file->f_pos = 0;
  33. return(fd);
  34. }

下面开始正式看发送数据的最顶层函数--sock_write()函数

  1. /*
  2. *  Write data to a socket. We verify that the user area ubuf..ubuf+size-1 is
  3. *  readable by the user process.
  4. */
  5. static int sock_write(struct inode *inode, struct file *file, char *ubuf, int size)
  6. {
  7. struct socket *sock;
  8. int err;
  9. if (!(sock = socki_lookup(inode))) //返回inode结构的对应的socket结构
  10. {
  11. printk("NET: sock_write: can't find socket for inode!\n");
  12. return(-EBADF);
  13. }
  14. if (sock->flags & SO_ACCEPTCON)
  15. return(-EINVAL);
  16. if(size<0)
  17. return -EINVAL;
  18. if(size==0)
  19. return 0;
  20. if ((err=verify_area(VERIFY_READ,ubuf,size))<0)
  21. return err;
  22. return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK)));//调用inet_write()函数
  23. }

inet_write()函数

  1. static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)
  2. {
  3. return inet_send(sock,ubuf,size,noblock,0);
  4. }

inet_send()函数

  1. static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,
  2. unsigned flags)
  3. {
  4. struct sock *sk = (struct sock *) sock->data;//从socket结构中取出sock指针
  5. if (sk->shutdown & SEND_SHUTDOWN)
  6. {
  7. send_sig(SIGPIPE, current, 1);
  8. return(-EPIPE);
  9. }
  10. if(sk->err)
  11. return inet_error(sk);
  12. /* We may need to bind the socket. */
  13. if(inet_autobind(sk)!=0)//自动分配本地端口号,并将sk根据端口号加入sock表中
  14. return(-EAGAIN);
  15. return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));//调用udp_write()函数
  16. }

这样系统就会调用传输层(还是以UDP为例)的函数udp_write()来发送数据,这样数据就从应用层到了传输层。下篇分析传输层向网络层的数据传输。