accept系統調用核心實現

來源:互聯網
上載者:User

標籤:blog   使用   os   io   檔案   資料   for   2014   

使用者態對accept的標準使用方法:if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)  {   //accept()函數讓server接收客戶的串連請求   perror("accept Error\n");   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,一次調用返回一個skstruct 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;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.