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. 转:git上传本地项目到github

    转自:https://blog.csdn.net/Lucky_LXG/article/details/77849212 将本地项目上传到Github(两种简单.方便的方法) 一.第一种方法:首先你需要 ...

  2. mysql 知识整理

    前言 安装 使用 关于mysql程式的linux命令 启动mysqld 检查端口是否运行 查看数据库程式相关信息 查看mysql版本 查看配置文件位置 登陆mysql 修改密码 SQL命令 查看数据库 ...

  3. 第四篇.python的基础

    目录 第四篇.python基础01 1. 变量 2. 常量 3. python变量内存管理 4. 变量的三个特征 5. 花式赋值 6. 注释 7. 数据类型基础 8. 数字类型 9. 字符串类型 10 ...

  4. sql分页查询(2005以后的数据库)和access分页查询

    sql分页查询: select * from ( select ROW_NUMBER() over(order by 排序条件) as rowNumber,* from [表名] where 条件 ) ...

  5. 分布式系统读写模型中的Quorum机制

    分布式系统的设计中会涉及到许多的协议.机制用来解决可靠性问题.数据一致性问题等,Quorum 机制就是其中的一种.我们通过分布式系统中的读写模型来简单介绍它. 分布式系统中的读写模型 分布式系统是由多 ...

  6. stackstorm docker中配置ssh免密码登录方式

    在docker中配置st2的ssh登录方式折腾了好久,今天终于彻底搞懂了如何重启容器后也不丢失之前的配置,只要容器起来后就可以正常ssh 执行st2中的remote-shell-script 和rem ...

  7. bom and dom

    bom:Broswer Object Model: 浏览器对象模型- navigator: 获取客户机的信息(浏览器的信息)document.write(navigator.appName);- sc ...

  8. BLE 5协议栈-安全管理层

    文章转载自:http://www.sunyouqun.com/2017/04/ 安全管理(Security Manager)定义了设备间的配对过程. 配对过程包括了配对信息交换.生成密钥和交换密钥三个 ...

  9. Oracle11g adump目录下面.aud增长导致空间撑满无法删除导致CRS无法启动的解决方法

    [root@node1 adump]# pwd /u01/app/oracle/admin/node/adump 大概有10000个文件 rm -rf * 屏幕显示: -bash: /bin/rm: ...

  10. TCP协议(包括TCP的连接过程,数据分段,TCP有关服务器优化)

    Transmission Control Protocol/Internet Protocol 传输控制协议/因特网互联协议 TCP/IP是一个Protocol Stack(协议栈),包括TCP.IP ...