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中要实现网 ...
随机推荐
- vue项目使用eslint
转载自 https://www.cnblogs.com/hahazexia/p/6393212.html eslint配置方式有两种: 注释配置:使用js注释来直接嵌入ESLint配置信息到一个文件里 ...
- P4071 [SDOI2016]排列计数
题目描述 求有多少种长度为 n 的序列 A,满足以下条件: 1 ~ n 这 n 个数在序列中各出现了一次 若第 i 个数 A[i] 的值为 i,则称 i 是稳定的.序列恰好有 m 个数是稳定的 满足条 ...
- python中使用%与.format格式化文本
初学python,看来零零碎碎的格式化文本的方法,总结一下python中格式化文本的方法.使用不当的地欢迎指出谢谢. 1.首先看使用%格式化文本 常见的占位符: 常见的占位符有: %d 整数 %f 浮 ...
- ORA-01410: 无效的 ROWID
视图查询单表是有这个东西的,但是视图的SQL涉及多表关联,就没这个rowid了,要么自己写个,要么不用这个ROWID做啥动作
- BZOJ2525 [Poi2011]Dynamite 【二分 + 贪心】
题目链接 BZOJ2525 题解 就是要求所有有炸弹的点到点燃点距离最大值最小 显然二分答案距离\(D\) 然后按深度排序,贪心点燃当前没覆盖的深度最深的点往上第\(D\)层的点 每覆盖一个点要标记其 ...
- python之旅:字符编码
一 了解字符编码的知识储备 一 计算机基础知识 知识储备:cpu.内存.硬盘 二 文本编辑器存取文件的原理(nodepad++,pycharm,word) #1.打开编辑器就打开了启动了一个进程,是在 ...
- WinterCamp2017吃饭睡觉记
noip考完后励志好好学习进HE队然后Au,就这样每天勤奋刻苦发愤图强不知不觉就到冬令营了. 除了我之外的大佬们都是以上经历. 我呢……一个很爱浪的蒟蒻. 冬令营到了,伟大的CCF本着报一个录一个的原 ...
- Python 不定参数函数
1. 元组形式 def test1(*args): print('################test1################') print(type(args)) print(arg ...
- python中的zip
>>> a = zip([1,2,3],[34,35,36]) >>> print(a) <zip object at 0x0394D0F8> > ...
- JVM加载一个类的过程
类的加载过程 Java源代码被编译成class字节码,JVM把描述类数据的字节码.Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机 ...