accept系统调用
accept系统调用完成的工作是,从已经完成三次握手的连接队列中取一个连接,进行后续服务;
调用过程中,会重新分配一个socket,以及关联文件和传输控制块,如果应用层需要获取对端信息,则将对端信息拷贝到用户空间;
- /*
- * 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.
- */
- SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
- int __user *, upeer_addrlen, int, flags)
- {
- struct socket *sock, *newsock;
- struct file *newfile;
- int err, len, newfd, fput_needed;
- struct sockaddr_storage address;
- /* 只支持cloexec和nonblock */
- if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
- return -EINVAL;
- /* 如果阻塞标记不等&& 有阻塞标记,则替换为O_NONBLOCK */
- if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
- flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
- /* 找到socket */
- sock = sockfd_lookup_light(fd, &err, &fput_needed);
- if (!sock)
- goto out;
- err = -ENFILE;
- /* 分配一个新socket */
- newsock = sock_alloc();
- if (!newsock)
- goto out_put;
- /* 类型和操作与本端socket相同 */
- 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);
- /* 获取新的文件描述符 */
- newfd = get_unused_fd_flags(flags);
- if (unlikely(newfd < )) {
- err = newfd;
- sock_release(newsock);
- goto out_put;
- }
- /* 分配新的文件 */
- newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
- if (IS_ERR(newfile)) {
- err = PTR_ERR(newfile);
- put_unused_fd(newfd);
- sock_release(newsock);
- goto out_put;
- }
- /* accept检查 */
- err = security_socket_accept(sock, newsock);
- if (err)
- goto out_fd;
- /* 执行具体的accept操作 */
- err = sock->ops->accept(sock, newsock, sock->file->f_flags, false);
- if (err < )
- goto out_fd;
- /* 指定了获取对端信息 */
- if (upeer_sockaddr) {
- if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
- &len, ) < ) {
- err = -ECONNABORTED;
- goto out_fd;
- }
- /* 拷贝对端地址到用户空间结构 */
- err = move_addr_to_user(&address,
- len, upeer_sockaddr, upeer_addrlen);
- if (err < )
- goto out_fd;
- }
- /* File flags are not inherited via accept() unlike another OSes. */
- /* 绑定描述符和文件 */
- fd_install(newfd, newfile);
- err = newfd;
- out_put:
- fput_light(sock->file, fput_needed);
- out:
- return err;
- out_fd:
- fput(newfile);
- put_unused_fd(newfd);
- goto out_put;
- }
- SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr,
- int __user *, upeer_addrlen)
- {
- return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, );
- }
inet_accept函数调用传输层的accept操作,并且返回新的连接控制块,新的连接控制块需要与新的socket进行关联,accept完成,将新socket的状态设置为已连接状态;
- /*
- * Accept a pending connection. The TCP layer now gives BSD semantics.
- */
- int inet_accept(struct socket *sock, struct socket *newsock, int flags,
- bool kern)
- {
- struct sock *sk1 = sock->sk;
- int err = -EINVAL;
- /* 执行传输层的accept操作 */
- struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err, kern);
- if (!sk2)
- goto do_err;
- lock_sock(sk2);
- /* rps处理 */
- sock_rps_record_flow(sk2);
- WARN_ON(!(( << sk2->sk_state) &
- (TCPF_ESTABLISHED | TCPF_SYN_RECV |
- TCPF_CLOSE_WAIT | TCPF_CLOSE)));
- /* 控制块连接到新的socket */
- sock_graft(sk2, newsock);
- /* 设置新socket的状态为连接 */
- newsock->state = SS_CONNECTED;
- err = ;
- release_sock(sk2);
- do_err:
- return err;
- }
- EXPORT_SYMBOL(inet_accept);
TCP层对于accept的实现,请移步另外一篇文章:<TCP层accept系统调用的实现分析>;
accept系统调用的更多相关文章
- accept系统调用内核实现
用户态对accept的标准使用方法: if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_siz ...
- TCP层accept系统调用的实现分析
inet_csk_accept函数实现了tcp协议accept操作,其主要完成的功能是,从已经完成三次握手的队列中取控制块,如果没有已经完成的连接,则需要根据阻塞标记来来区分对待,若非阻塞则直接返回, ...
- Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()
前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编 ...
- linux独有的sendfile系统调用--“零拷贝,高效”
参考:http://blog.csdn.net/caianye/article/details/7576198 如今几乎每个人都听说过Linux中所谓的"零拷贝"特性,然而我经常碰 ...
- socket编程之accept()函数【转载】
名称 accept() 接收一个套接字中已建立的连接 使用格式 #include <sys/types.h> #include <sys/socket.h> int accep ...
- Netty源码细节-accept、read(Linux os层 + Netty层代码细节)(转)
原文:http://budairenqin.iteye.com/blog/2215899 这篇分析一下accept的细节, 我觉得网络IO相关开发很多时候不能仅仅局限于java层, 尤其从accept ...
- 从Linux源码看Socket(TCP)的accept
从Linux源码看Socket(TCP)的accept 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就从Linux源码的角度看下Serve ...
- socket 函数
1.创建套接字并返回一个描述符,该描述符可以用来访问套接字 #include<sys/types.h> #include<sys/socket.h> int socket(i ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
随机推荐
- path变量修改后无法保存
Eclipse启动时出现错误: A Java Runtime Environment (JRE) or Java Development Kit(JDK) must be available in o ...
- MySql--学习成长过程
MySql--学习成长过程 模拟测试: QQ数据库管理 一.创建数据库并添加关系和测试数据 1 ##创建QQ数据库,完成简单的测试 2 3 #创建数据库 4 DROP DATABASE IF EXIS ...
- static变量 方法 类 和final
static变量:声明为static的变量实质上就是全局变量.当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量.静态变量与静态方法类似.所有此类实例共 ...
- BZOJ 4454: C Language Practice
4454: C Language Practice Time Limit: 20 Sec Memory Limit: 24 MBSubmit: 501 Solved: 112[Submit][St ...
- NetApp常用巡检命令
常用检查命令 environment status 查看环境信息 version 查看OS版本 sysconfig -v 查看系统信息(设备序列号 系统软.硬件信息等) sysconfig -a 查看 ...
- 【codeforces 528D】 Fuzzy Search
http://codeforces.com/problemset/problem/528/D (题目链接) 题意 给定母串和模式串,字符集大小为${4}$,给定${k}$,模式串在某个位置匹配当且仅当 ...
- 《Linux内核设计与实现》学习总结 Chap3
第三章 进程管理 进程是Unix操作系统抽象概念中最基本的一种.我们拥有操作系统就是为了运行用户程序,因此,进程管理就是所有操作系统的心脏所在. 3.1进程 概念: 进程:处于执行期的程序.但不仅局限 ...
- sqoop 补充
1.用 sqoop 将MySQL中的数据导入hbase中 sqoop import \--connect jdbc:mysql://***.***.*.***:3306/mysql \--hbase- ...
- getopt_long
http://blog.csdn.net/lanyan822/article/details/7692013 在程序中难免需要使用命令行选项,可以选择自己解析命令行选项,但是有现成的,何必再造轮子.下 ...
- 【Asp.net入门15】第一个Asp.net应用程序-输入验证
前言 所谓输入验证,顾名思义就是验证用户输入符不符合要求.前面我们已经完成了这个简单的应用程序,但还有一个问题需要解决:用户可以在Default.aspx窗体中 提交任何数据,甚至可以提交根本不包含任 ...