Chinaunix首页 | 论坛 | 博客
  • 博客访问: 218429
  • 博文数量: 30
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 476
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-07 18:15
个人简介

程序员一个。14年毕业。

文章分类

全部博文(30)

文章存档

2014年(13)

2013年(17)

我的朋友

分类: C/C++

2014-07-20 00:55:04



点击(此处)折叠或打开

  1. 用户态对accept的标准用法:
  2. if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)
  3.   {
  4.    //accept()函数让服务器接收客户的连接请求
  5.    perror("accept Error\n");
  6.    continue;
  7.   }
  8. sockfd是通过socket系统调用,并且经过listen过的套接字:
  9. sockfd = socket(AF_INET, SOCK_STREAM, 0)
  10. listen(sockfd, 128)

  11. remote_addr将会存储远端设备的地址信息。

  12. /*
  13.  *    For accept, we attempt to create a new socket, set up the link
  14.  *    with the client, wake up the client, then return the new
  15.  *    connected fd. We collect the address of the connector in kernel
  16.  *    space and move it to user at the very end. This is unclean because
  17.  *    we open the socket then return an error.
  18.  *
  19.  *    1003.1g adds the ability to recvmsg() to query connection pending
  20.  *    status to recvmsg. We need to add that support in a way thats
  21.  *    clean when we restucture accept also.
  22.  */

  23. asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
  24.       int __user *upeer_addrlen)
  25. {
  26.  struct socket *sock, *newsock;
  27.  struct file *newfile;
  28.  int err, len, newfd, fput_needed;
  29.  char address[MAX_SOCK_ADDR];

  30. //通过监听套接字的描述符fd,找到监听套接字
  31.  sock = sockfd_lookup_light(fd, &err, &fput_needed);
  32.  if (!sock)
  33.   goto out;

  34.  err = -ENFILE;
  35. //创建新的socket,即心的套接字,它将被client_fd 描述,用于传输数据,
  36. //也就是accept系统调用返回值client_fd 所对应的套接口
  37.  if (!(newsock = sock_alloc()))
  38.   goto out_put;

  39. //继承listen_fd对应的的一些属性,包括套接字类型,和操作。
  40. //不难理解,listen_fd和client_fd 对应的套接口都是tcp,这些不用一一赋值,直接用listen_fd的属性即可。
  41.  newsock->type = sock->type;
  42.  newsock->ops = sock->ops;

  43.  /*
  44.   * We don't need try_module_get here, as the listening socket (sock)
  45.   * has the protocol module (sock->ops->owner) held.
  46.   */
  47. //不懂
  48.  __module_get(newsock->ops->owner);

  49. //创建新的file,然后返回newfd ,这个fd就是待会被返回的client_fd
  50. //到现在为止,这个newfd和newfile是有关联的。
  51.  newfd = sock_alloc_fd(&newfile);
  52.  if (unlikely(newfd < 0)) {
  53.   err = newfd;
  54.   sock_release(newsock);
  55.   goto out_put;
  56.  }
  57. //使得这个newsock绑定刚才新建的newfile
  58. //即现在为止,newfd newfile newsock之间是有关联的
  59.  err = sock_attach_fd(newsock, newfile);
  60.  if (err < 0)
  61.   goto out_fd_simple;

  62.  err = security_socket_accept(sock, newsock);
  63.  if (err)
  64.   goto out_fd;
  65. //newsock是socket结构体,sock->ops->accept的目的是为newsock关联一个sock结构体
  66. //即三次握手结束后,新建的sock传输控制块,它等待用户accept系统调用“领养”它。
  67. //sock->ops->accept对应的函数是inet_accept
  68.  err = sock->ops->accept(sock, newsock, sock->file->f_flags);
  69.  if (err < 0)
  70.   goto out_fd;

  71.  if (upeer_sockaddr) {
  72.   if (newsock->ops->getname(newsock, (struct sockaddr *)address,
  73.        &len, 2) < 0) {
  74.    err = -ECONNABORTED;
  75.    goto out_fd;
  76.   }
  77.   err = move_addr_to_user(address, len, upeer_sockaddr,
  78.      upeer_addrlen);
  79.   if (err < 0)
  80.    goto out_fd;
  81.  }
  82. .........................................
  83. }

  84. /*
  85.  *    Accept a pending connection. The TCP layer now gives BSD semantics.
  86.  */
  87. int inet_accept(struct socket *sock, struct socket *newsock, int flags)
  88. {
  89. //第一个参数sock是监听套接字代表的套接字
  90. //newsock是刚才我们新建的套接字,用以描述数据传输
  91. //显然,此函数的目的,是找到通过套接字,找到套接字上挂着的以及完成三次握手的sk
  92. //这个被找到的sk,将被关联到newsock

  93. //sk1 是监听套接字对应的传输控制块
  94.  struct sock *sk1 = sock->sk;
  95.  int err = -EINVAL;

  96. //sk2(三次握手后建立的传输控制块) 是挂在sk1(监听套接字的传输控制块) 中的完成三次握手后的sk
  97. // sk1->sk_prot->accept 对应的函数是inet_csk_accept
  98.  struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err);

  99.  if (!sk2)
  100.   goto do_err;

  101.  lock_sock(sk2);

  102.  WARN_ON(!((1 << sk2->sk_state) &
  103.     (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE)));

  104. //这个被找到的sk,将被关联到newsock
  105. //三次握手后建立的传输控制块sk(sock 结构体),是不对应任何socket结构体的,所以我们关联上
  106. //这样三次握手后建立的传输控制块sk,就和文件系统有关联了
  107. //关联上后,我们就能对其调用send,recvfrom等系统调用了
  108.  sock_graft(sk2, newsock);

  109.  newsock->state = SS_CONNECTED;
  110.  err = 0;
  111.  release_sock(sk2);
  112. do_err:
  113.  return err;
  114. }

  115. /*
  116.  * This will accept the next outstanding connection.
  117.  */
  118. //inet_csk_accept的功能时获取建立3次握手后的sk,一次调用返回一个sk
  119. struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
  120. {
  121. //第一个参数是监听套接字对应的传输控制块。
  122.  struct inet_connection_sock *icsk = inet_csk(sk);
  123.  struct sock *newsk;
  124.  int error;

  125.  lock_sock(sk);

  126.  /* We need to make sure that this socket is listening,
  127.   * and that it has something pending.
  128.   */
  129.  error = -EINVAL;
  130. //如果你传进的参数正确,监听套接字对应的传输控制块的状态,肯定是TCP_LISTEN
  131.  if (sk->sk_state != TCP_LISTEN)
  132.   goto out_err;

  133.  /* Find already established connection */
  134. //icsk->icsk_accept_queue挂的是request_sock,request_sock上挂的就是三次握手后新建的sk
  135. //reqsk_queue_empty(&icsk->icsk_accept_queue)判断是否空,就进入if,如何设置为阻塞,则休眠
  136.  if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
  137.   long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);

  138.   /* If this is a non blocking socket don't sleep */
  139.   error = -EAGAIN;
  140.   if (!timeo)
  141.    goto out_err;

  142.   error = inet_csk_wait_for_connect(sk, timeo);
  143.   if (error)
  144.    goto out_err;
  145.  }

  146. //reqsk_queue_get_child的逻辑是:
  147. //1:取出icsk_accept_queue的request_sock,然后取出request_sock中的sk
  148. //2:listen的sk中,sk_ack_backlog计数减一,sk->sk_ack_backlog--,因为sk_ack_backlog有上限。
  149. //3:删除request_sock
  150. //4:return取出的sk
  151.  newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
  152.  WARN_ON(newsk->sk_state == TCP_SYN_RECV);
  153. out:
  154.  release_sock(sk);
  155.  return newsk;
  156. out_err:
  157.  newsk = NULL;
  158.  *err = error;
  159.  goto out;
  160. }

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