inet_csk_accept函数实现了tcp协议accept操作,其主要完成的功能是,从已经完成三次握手的队列中取控制块,如果没有已经完成的连接,则需要根据阻塞标记来来区分对待,若非阻塞则直接返回,若阻塞则需要在一定时间范围内阻塞等待;

 /*
* This will accept the next outstanding connection.
*/
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct request_sock_queue *queue = &icsk->icsk_accept_queue;
struct request_sock *req;
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; /* 不是listen状态 */
if (sk->sk_state != TCP_LISTEN)
goto out_err; /* Find already established connection */ /* 还没有已完成的连接 */
if (reqsk_queue_empty(queue)) { /* 获取等待时间,非阻塞为0 */
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;
} /* 从已完成连接队列中移除 */
req = reqsk_queue_remove(queue, sk); /* 设置新控制块指针 */
newsk = req->sk; /* TCP协议 && fastopen */
if (sk->sk_protocol == IPPROTO_TCP &&
tcp_rsk(req)->tfo_listener) {
spin_lock_bh(&queue->fastopenq.lock);
if (tcp_rsk(req)->tfo_listener) {
/* We are still waiting for the final ACK from 3WHS
* so can't free req now. Instead, we set req->sk to
* NULL to signify that the child socket is taken
* so reqsk_fastopen_remove() will free the req
* when 3WHS finishes (or is aborted).
*/
req->sk = NULL;
req = NULL;
}
spin_unlock_bh(&queue->fastopenq.lock);
}
out:
release_sock(sk); /* 释放请求控制块 */
if (req)
reqsk_put(req); /* 返回找到的连接控制块 */
return newsk;
out_err:
newsk = NULL;
req = NULL;
*err = error;
goto out;
}

如果请求队列中没有已完成握手的连接,并且套接字已经设置了阻塞标记,则需要加入调度队列等待连接的到来,inet_csk_wait_for_connect函数完成了这个功能;

 /*
* Wait for an incoming connection, avoid race conditions. This must be called
* with the socket locked.
*/
static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
{
struct inet_connection_sock *icsk = inet_csk(sk);
DEFINE_WAIT(wait);
int err; /*
* True wake-one mechanism for incoming connections: only
* one process gets woken up, not the 'whole herd'.
* Since we do not 'race & poll' for established sockets
* anymore, the common case will execute the loop only once.
*
* Subtle issue: "add_wait_queue_exclusive()" will be added
* after any current non-exclusive waiters, and we know that
* it will always _stay_ after any new non-exclusive waiters
* because all non-exclusive waiters are added at the
* beginning of the wait-queue. As such, it's ok to "drop"
* our exclusiveness temporarily when we get woken up without
* having to remove and re-insert us on the wait queue.
*/
for (;;) { /* 加入等待队列 */
prepare_to_wait_exclusive(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
release_sock(sk); /* 如果为空计算,进行调度 */
if (reqsk_queue_empty(&icsk->icsk_accept_queue))
timeo = schedule_timeout(timeo);
sched_annotate_sleep();
lock_sock(sk);
err = ;
/* 队列不为空*/
if (!reqsk_queue_empty(&icsk->icsk_accept_queue))
break;
err = -EINVAL;
/* 连接状态不是LISTEN */
if (sk->sk_state != TCP_LISTEN)
break;
/* 信号打断 */
err = sock_intr_errno(timeo);
if (signal_pending(current))
break;
err = -EAGAIN;
/* 调度超时 */
if (!timeo)
break;
}
/* 结束等待 */
finish_wait(sk_sleep(sk), &wait);
return err;
}

reqsk_queue_remove函数完成了将完成握手的控制块从请求队列移除的工作;

 static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue *queue,
struct sock *parent)
{
struct request_sock *req; spin_lock_bh(&queue->rskq_lock); /* 找到队列头 */
req = queue->rskq_accept_head;
if (req) {
/* 减少已连接计数 */
sk_acceptq_removed(parent);
/* 头部指向下一节点 */
queue->rskq_accept_head = req->dl_next; /* 队列为空 */
if (queue->rskq_accept_head == NULL)
queue->rskq_accept_tail = NULL;
}
spin_unlock_bh(&queue->rskq_lock);
return req;
}

TCP层accept系统调用的实现分析的更多相关文章

  1. TCP层sendmsg系统调用的实现分析

    概述 sendmsg系统调用在tcp层的实现是tcp_sendmsg函数,该函数完成以下任务:从用户空间读取数据,拷贝到内核skb,将skb加入到发送队列的任务,调用发送函数:函数在执行过程中会锁定控 ...

  2. TCP层recvmsg系统调用的实现分析

    概述 recvmsg系统调用在tcp层的实现是tcp_recvmsg函数,该函数完成从接收队列中读取数据复制到用户空间的任务:函数在执行过程中会锁定控制块,避免软中断在tcp层的影响:函数会涉及从接收 ...

  3. TCP层shutdown系统调用的实现分析

    概述 shutdown系统调用在tcp层会调用两个函数,对于ESTABLISHED状态需要调用tcp_shutdown关闭连接,对于LISTEN和SYN_SENT状态则需要以非阻塞模式调用tcp_di ...

  4. TCP层close系统调用的实现分析

    在调用close系统调用关闭套接字时,如果套接字引用计数已经归零,则需继续向上层调用其close实现,tcp为tcp_close:本文仅介绍tcp部分,前置部分请参考本博关于close系统调用的文章: ...

  5. TCP层bind系统调用的实现分析

    说明:该文章中部分代码未能完全理解透彻,可能对您造成误解,请慎读: 并建议您先阅读本博另外一篇文章:<Linux TCP套接字选项 之 SO_REUSEADDR && SO_RE ...

  6. accept系统调用

    /* * For accept, we attempt to create a new socket, set up the link * with the client, wake up the c ...

  7. Python Tornado框架(TCP层)

    Tornado在TCP层里的工作机制 上一节是关于应用层的协议 HTTP,它依赖于传输层协议 TCP,例如服务器是如何绑定端口的?HTTP 服务器的 handle_stream 是在什么时候被调用的呢 ...

  8. 从Linux源码看Socket(TCP)的accept

    从Linux源码看Socket(TCP)的accept 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就从Linux源码的角度看下Serve ...

  9. accept系统调用内核实现

    用户态对accept的标准使用方法: if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_siz ...

随机推荐

  1. centos 配置mysql主从复制

    mysql+centos7+主从复制   MYSQL(mariadb) MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.开发这个分支的原因之一是:甲骨文公 ...

  2. 打印从1到最大的n位数(考虑大数问题)

    void Print1ToMaxOfNDigits(int n) { if(n <= 0) { return; } int * number = new int[n]; for(int i = ...

  3. 关于mysql installer 的安装和环境变量配置

    MySQL针对不同的用户提供了2中不同的版本: MySQL Community Server:社区版.由MySQL开源社区开发者和爱好者提供技术支持,对开发者开放源代码并提供免费下载. MySQL E ...

  4. win10下当前目录右键添加CMD快捷方式

    在某个文件夹下右键打开cmd,这样不用每次都在默认情况下切换目录.无奈win10 1703版本下shift+右键不能打开cmd,只能打开powershell. 首先,在桌面新建一个文本文档. Wind ...

  5. 盗取连接你wifi的人的qq

    #本文内容仅供个人娱乐学习 思路: 使用wireshark监听笔记本的wifi热点,拦截捕获连接你的wifi热点的人的手机qq网络数据包,从网络数据包中分析取出两个qq空间的两个coookie值,使用 ...

  6. thinkphp5.0 field和with连用的问题

    field在with后面时field会不起作用,会查询数据库中全部的字段: field在with前面时会无法筛选联表的字段 解决办法把with换成join,field和join顺序无所谓 * @par ...

  7. shell脚本基础和grep文本处理工具企业应用3

    文本处理工具:    linux上文本处理三剑客        grep,egrep,fgrep:文本过滤工具(模式:pattern)工具            grep:默认支持的是基本正则表达式: ...

  8. Hive压缩和存储(十二)

    压缩和存储 1. Hadoop压缩配置 1) MR支持的压缩编码 压缩格式 工具 算法 文件扩展名 是否可切分 DEFAULT 无 DEFAULT .deflate 否 Gzip gzip DEFAU ...

  9. 【input】标签去除默认样式

    input{-webkit-appearance: none; -moz-appearance: none; -o-appearance: none; appearance: none;}

  10. Gym - 101955E The Kouga Ninja Scrolls (曼哈顿距离变换+线段树)

    题意:有n个忍者(编号为1-n),每个忍者有三个属性:横坐标x,纵坐标y,所属门派c,要求支持三种操作: 1.改变第k个忍者的位置 2.改变第k个忍者的门派 3.查询编号为[l,r]之间的忍者中,所属 ...