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中要实现网 ...
随机推荐
- 查看MySQL最近执行的语句
首先登入MySQL. Reading table information for completion of table and column names You can turn off this ...
- BZOJ 3190 赛车 | 计算几何
BZOJ 3190 赛车 题面 这里有一辆赛车比赛正在进行,赛场上一共有N辆车,分别称为个g1,g2--gn.赛道是一条无限长的直线.最初,gi位于距离起跑线前进ki的位置.比赛开始后,车辆gi将会以 ...
- AC自动机【萌新文章】
我这个蒟蒻第一次写博客,有点小激动呢. 主要是最近刚学了AC自动机,学得糟糟糕糕,记录一下,看到dalao们都在写博客,决定自己也写一波[我好水的啦,写的也不好] AC自动机大概就是 Trie+ ...
- debian修改默认编辑器
刚才在一台机器上打开 crontab -e,跳出来的编辑器是nano,太难使... 在debian下是使用 update-alternatives 命令修改默认编辑器. 先查看一下使用帮助 # upd ...
- 旧题新做:从idy的视角看数据结构
“今天你不写总结……!!!” 额…… 还是讲我的吧.这些考试都是idy出的题. 20170121:DFS序. ST表.线段树练习 这是第一次考数据结构. Problem 1. setsum 1 sec ...
- 布隆过滤器 Bloom Filter
使用普通集合来判断一个元素是否已存在于集合中,需要占用比较大的空间.而使用Bloom Filter 可有效节省空间. Bloom Filter 以较少的内存占用及较小的误判率达到判断元素是否存已经加入 ...
- bzoj 5015 [Snoi2017]礼物 矩阵乘法
5015: [Snoi2017]礼物 Time Limit: 15 Sec Memory Limit: 512 MBSubmit: 163 Solved: 115[Submit][Status][ ...
- 字典的setdefault() 和get()方法比较
Python 字典 setdefault() 函数 和get() 类似: 如果键存在字典中,返回其value值 如果键不存在字典中,创建键值对.完后,返回值为默认值. 话不多说,上栗子: setdef ...
- NOI2006 最大获利(最大权闭合子图)
codevs 1789 最大获利 2006年NOI全国竞赛 时间限制: 2 s 空间限制: 128000 KB 题目描述 Description 新的技术正冲击着手机通讯市场,对于各大运营商来 ...
- 数学建模 数据包络分析(DEA) Lingo实现
model: sets: dmu/../:lambda; !决策单元; inw/../:s1; !投入变量集; outw/../:s2; !产出变量集; inv(inw, dmu):x; !投入数据; ...