zoukankan      html  css  js  c++  java
  • accept系统调用内核实现

    用户态对accept的标准使用方法:
    if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)
      {
       //accept()函数让server接收客户的连接请求
       perror("accept Error
    ");
       continue;
      }
    sockfd是通过socket系统调用,而且经过listen过的套接字:
    sockfd = socket(AF_INET, SOCK_STREAM, 0)
    listen(sockfd, 128)
    
    remote_addr将会存储远端设备的地址信息。
    
    /*
     *	For accept, we attempt to create a new socket, set up the link
     *	with the client, wake up the client, then return the new
     *	connected fd. We collect the address of the connector in kernel
     *	space and move it to user at the very end. This is unclean because
     *	we open the socket then return an error.
     *
     *	1003.1g adds the ability to recvmsg() to query connection pending
     *	status to recvmsg. We need to add that support in a way thats
     *	clean when we restucture accept also.
     */
    
    asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
          int __user *upeer_addrlen)
    {
     struct socket *sock, *newsock;
     struct file *newfile;
     int err, len, newfd, fput_needed;
     char address[MAX_SOCK_ADDR];
    
    //通过监听套接字的描写叙述符fd,找到监听套接字
     sock = sockfd_lookup_light(fd, &err, &fput_needed);
     if (!sock)
      goto out;
    
     err = -ENFILE;
    //创建新的socket,即心的套接字,它将被client_fd 描写叙述,用于数据传输,
    //也就是accept系统调用返回值client_fd 所相应的套接口
     if (!(newsock = sock_alloc()))
      goto out_put;
    
    //继承listen_fd相应的的一些属性,包含套接字类型,和操作。
    //不难理解,listen_fd和client_fd 相应的套接口都是tcp,这些不用一一赋值,直接用listen_fd的属性就可以。
     newsock->type = sock->type;
     newsock->ops = sock->ops;
    
     /*
      * We don't need try_module_get here, as the listening socket (sock)
      * has the protocol module (sock->ops->owner) held.
      */
    //不懂
     __module_get(newsock->ops->owner);
    
    //创建新的file,然后返回newfd ,这个fd就是待会被返回的client_fd 
    //到如今为止,这个newfd和newfile是有关联的。
     newfd = sock_alloc_fd(&newfile);
     if (unlikely(newfd < 0)) {
      err = newfd;
      sock_release(newsock);
      goto out_put;
     }
    //使得这个newsock绑定刚才新建的newfile
    //即如今为止,newfd  newfile newsock之间是有关联的
     err = sock_attach_fd(newsock, newfile);
     if (err < 0)
      goto out_fd_simple;
    
     err = security_socket_accept(sock, newsock);
     if (err)
      goto out_fd;
    //newsock是socket结构体,sock->ops->accept的目的是为newsock关联一个sock结构体
    //即三次握手结束后,新建的sock传输控制块,它等待用户accept系统调用“领养”它。
    //sock->ops->accept相应的函数是inet_accept
     err = sock->ops->accept(sock, newsock, sock->file->f_flags);
     if (err < 0)
      goto out_fd;
    
     if (upeer_sockaddr) {
      if (newsock->ops->getname(newsock, (struct sockaddr *)address,
           &len, 2) < 0) {
       err = -ECONNABORTED;
       goto out_fd;
      }
      err = move_addr_to_user(address, len, upeer_sockaddr,
         upeer_addrlen);
      if (err < 0)
       goto out_fd;
     }
    .........................................
    }
    
    /*
     *	Accept a pending connection. The TCP layer now gives BSD semantics.
     */
    int inet_accept(struct socket *sock, struct socket *newsock, int flags)
    {
    //第一个參数sock是监听套接字代表的套接字
    //newsock是刚才我们新建的套接字,用以描写叙述数据传输
    //显然,此函数的目的,是找到通过套接字,找到套接字上挂着的以及完毕三次握手的sk
    //这个被找到的sk,将被关联到newsock
    
    //sk1 是监听套接字相应的传输控制块
     struct sock *sk1 = sock->sk;
     int err = -EINVAL;
    
    //sk2(三次握手后建立的传输控制块) 是挂在sk1(监听套接字的传输控制块) 中的完毕三次握手后的sk
    // sk1->sk_prot->accept 相应的函数是inet_csk_accept
     struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err);
    
     if (!sk2)
      goto do_err;
    
     lock_sock(sk2);
    
     WARN_ON(!((1 << sk2->sk_state) &
        (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE)));
    
    //这个被找到的sk,将被关联到newsock
    //三次握手后建立的传输控制块sk(sock 结构体),是不正确应不论什么socket结构体的,所以我们关联上
    //这样三次握手后建立的传输控制块sk,就和文件系统有关联了
    //关联上后,我们就能对其调用send,recvfrom等系统调用了
     sock_graft(sk2, newsock);
    
     newsock->state = SS_CONNECTED;
     err = 0;
     release_sock(sk2);
    do_err:
     return err;
    }
    
    /*
     * This will accept the next outstanding connection.
     */
    //inet_csk_accept的功能时获取建立3次握手后的sk,一次调用返回一个sk
    struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
    {
    //第一个參数是监听套接字相应的传输控制块。
     struct inet_connection_sock *icsk = inet_csk(sk);
     struct sock *newsk;
     int error;
    
     lock_sock(sk);
    
     /* We need to make sure that this socket is listening,
      * and that it has something pending.
      */
     error = -EINVAL;
    //假设你传进的參数正确,监听套接字相应的传输控制块的状态,肯定是TCP_LISTEN
     if (sk->sk_state != TCP_LISTEN)
      goto out_err;
    
     /* Find already established connection */
    //icsk->icsk_accept_queue挂的是request_sock,request_sock上挂的就是三次握手后新建的sk
    //reqsk_queue_empty(&icsk->icsk_accept_queue)推断是否空,就进入if,怎样设置为堵塞,则休眠
     if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
      long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
    
      /* If this is a non blocking socket don't sleep */
      error = -EAGAIN;
      if (!timeo)
       goto out_err;
    
      error = inet_csk_wait_for_connect(sk, timeo);
      if (error)
       goto out_err;
     }
    
    //reqsk_queue_get_child的逻辑是:
    //1:取出icsk_accept_queue的request_sock,然后取出request_sock中的sk
    //2:listen的sk中,sk_ack_backlog计数减一,sk->sk_ack_backlog--,由于sk_ack_backlog有上限。
    //3:删除request_sock
    //4:return取出的sk
     newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
     WARN_ON(newsk->sk_state == TCP_SYN_RECV);
    out:
     release_sock(sk);
     return newsk;
    out_err:
     newsk = NULL;
     *err = error;
     goto out;
    }
    

  • 相关阅读:
    Java的静态块与实例块(转)
    Programming Ability Test学习 1031. Hello World for U (20)
    Programming Ability Test学习 1011. World Cup Betting (20)
    Programming Ability Test学习 1027. Colors in Mars (20)
    Programming Ability Test学习 1064. Complete Binary Search Tree (30)
    Programming Ability Test学习 1008. Elevator (20)
    【maven详解-生命周期】Maven的生命周期和插件
    【maven详解-插件】maven插件学习之源码插件Source Xref
    $(document).ready(){}、$(fucntion(){})、(function(){})(jQuery)onload()的区别
    你还没真的努力过,就轻易输给了懒惰
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/3901351.html
Copyright © 2011-2022 走看看