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中要实现网 ...
随机推荐
- 对HashMap的理解(三):ConcurrentHashMap
HashMap不是线程安全的.在并发插入元素的时候,有可能出现环链表,让下一次读操作出现死循环.避免HashMap的线程安全问题有很多方法,比如改用HashTable或Collections.sync ...
- static变量 方法 类 和final
static变量:声明为static的变量实质上就是全局变量.当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量.静态变量与静态方法类似.所有此类实例共 ...
- 只会java,参加acm如何?
作者:董适链接:https://www.zhihu.com/question/31213070/answer/51054677来源:知乎著作权归作者所有,转载请联系作者获得授权. 当然合适,有什么不合 ...
- python中使用%与.format格式化文本
初学python,看来零零碎碎的格式化文本的方法,总结一下python中格式化文本的方法.使用不当的地欢迎指出谢谢. 1.首先看使用%格式化文本 常见的占位符: 常见的占位符有: %d 整数 %f 浮 ...
- hihocoder1711 评论框排版[并查集+set]
#include <cstdio> #include <iostream> #include <set> using namespace std; ; struct ...
- win7下解决烦人的管理员权限问题
禁不住诱惑,用上win7了.可是,对system下的文件进行编辑时候,老是碰到什么必须拥有管理员权限才能进行操作,删除文件或者文件夹也遇到一样的问题.我就纳闷了,我不就是超级管理员吗?我怎么就没有权限 ...
- [UVALive 2678] Subsequence
图片加载可能有点慢,请跳过题面先看题解,谢谢 在切水题的道路上狂奔,一发不可收拾... 这道题好像不用写什么题解吧,吐个槽什么的算了 一眼题,大佬们都不屑于做,只有我这种弱菜才来写这种题目玩儿 记个前 ...
- BZOJ 3230 相似子串 | 后缀数组 二分 ST表
BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...
- 图解HTTP(六)HTTP首部
一.HTTP报文的结构: 二.4种首部字段: 1. 通用首部字段 请求报文和响应报文都会使用的首部. 首部字段名 说明 Cache-Control 控制缓存行为 Connection 逐跳首部.连接的 ...
- git<add的作用>
git add是个多功能的命令 1,跟踪: git add:跟踪当前目录下所有文件 git add <filename>:跟踪文件<filename> 2,暂存已修改的文件: ...