accept系统调用内核实现
生活随笔
收集整理的這篇文章主要介紹了
accept系统调用内核实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
用戶態對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_accepterr = 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_acceptstruct 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_LISTENif (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取出的sknewsk = 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;
}
轉載于:https://www.cnblogs.com/mfrbuaa/p/3901351.html
總結
以上是生活随笔為你收集整理的accept系统调用内核实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于在linux python源文件头部
- 下一篇: 九、linux文件系统