博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
accept系统调用内核实现
阅读量:6040 次
发布时间:2019-06-20

本文共 4677 字,大约阅读时间需要 15 分钟。

用户态对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;}

转载地址:http://ldrhx.baihongyu.com/

你可能感兴趣的文章
学习vue中遇到的报错,特此记录下来
查看>>
CentOS7 编译安装 Mariadb
查看>>
jstl格式化时间
查看>>
一则关于运算符的小例
查看>>
centos7 ambari2.6.1.5+hdp2.6.4.0 大数据集群安装部署
查看>>
cronexpression 详解
查看>>
一周小程序学习 第1天
查看>>
小孩的linux
查看>>
SpringMVC、MyBatis声明式事务管理
查看>>
开发者详解:端游及手游服务端的常用架构
查看>>
JavaScript History对象
查看>>
在 Windows 下安装 Oracle 11g XE (Express Edition)
查看>>
ListView优化
查看>>
【原创】 PostgreSQL 实现MySQL 的auto_increment 字段
查看>>
vs2015添加vc助手
查看>>
检测点1.1
查看>>
android--------阿里 AndFix 热修复
查看>>
control.add()
查看>>
Sublime text3中配置Github
查看>>
Asp.net,C# 加密解密字符串
查看>>