TCP层accept系统调用的实现分析
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系统调用的实现分析的更多相关文章
- TCP层sendmsg系统调用的实现分析
概述 sendmsg系统调用在tcp层的实现是tcp_sendmsg函数,该函数完成以下任务:从用户空间读取数据,拷贝到内核skb,将skb加入到发送队列的任务,调用发送函数:函数在执行过程中会锁定控 ...
- TCP层recvmsg系统调用的实现分析
概述 recvmsg系统调用在tcp层的实现是tcp_recvmsg函数,该函数完成从接收队列中读取数据复制到用户空间的任务:函数在执行过程中会锁定控制块,避免软中断在tcp层的影响:函数会涉及从接收 ...
- TCP层shutdown系统调用的实现分析
概述 shutdown系统调用在tcp层会调用两个函数,对于ESTABLISHED状态需要调用tcp_shutdown关闭连接,对于LISTEN和SYN_SENT状态则需要以非阻塞模式调用tcp_di ...
- TCP层close系统调用的实现分析
在调用close系统调用关闭套接字时,如果套接字引用计数已经归零,则需继续向上层调用其close实现,tcp为tcp_close:本文仅介绍tcp部分,前置部分请参考本博关于close系统调用的文章: ...
- TCP层bind系统调用的实现分析
说明:该文章中部分代码未能完全理解透彻,可能对您造成误解,请慎读: 并建议您先阅读本博另外一篇文章:<Linux TCP套接字选项 之 SO_REUSEADDR && SO_RE ...
- accept系统调用
/* * For accept, we attempt to create a new socket, set up the link * with the client, wake up the c ...
- Python Tornado框架(TCP层)
Tornado在TCP层里的工作机制 上一节是关于应用层的协议 HTTP,它依赖于传输层协议 TCP,例如服务器是如何绑定端口的?HTTP 服务器的 handle_stream 是在什么时候被调用的呢 ...
- 从Linux源码看Socket(TCP)的accept
从Linux源码看Socket(TCP)的accept 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就从Linux源码的角度看下Serve ...
- accept系统调用内核实现
用户态对accept的标准使用方法: if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_siz ...
随机推荐
- Const指针 、 指向const的指针 、引用、指针
1. const指针和 指向const的指针 指向const的指针: 不允许通过指针来改变其指向的const值 const double *cptr *cptr = 42; // error! 指针 ...
- 记项目管理大作业Web项目Mandrian的全流程[其一] 整体分析: 功能划分, 组织结构
Mandrian是个图书管理系统, 具体需求老师给出 这个项目的目的主要是管理过程和高层设计的学习和实践 11人小组, 路人局 成员调查 这里由于很多人我都不认识, 所以我提前发了一个能力调查表, 调 ...
- ES6基础之——new Set
Set 对象存储的值总是唯一的 Set 对象方法 方法 描述 add 添加某个值,返回Set对象本身. clear 删除所有的键/值对,没有返回值. delete 删除某个键,返回true.如果删除失 ...
- 2.OR Mapping 介绍
定义: ORM(Object Relational Mapping) -- 是一种为了解决面向对象与关系型数据库存在的互不匹配的现象的技术. 简单说:ORM是通过使用描述对象和数据库之间的映射的元数据 ...
- linux(centos7) 查看磁盘空间大小
命令: df -hl 1 显示: 文件系统 容量 已用 可用 已用% 挂载点 Filesystem Size Used Avail Use% Mounted on /dev/hda2 45G 19G ...
- kbmMW 5.09.00是个必须升级的版本!
这几天遇到的几个问题,从5.08.10升级到5.09.00,自然解决了! 所以建议大家都升级到这个版本. 例如我遇到的问题: 1.在线程中使用ClientQuery注意的问题 2.Invalid pr ...
- 使用wget下载百度云资源
目录 使用wget下载百度云资源 一.材料准备: 二.步骤 三.总结 使用wget下载百度云资源 一.材料准备: [BaiduPan explorer]谷歌插件,可以加载文件的真实下载地址 [Chro ...
- 怎么提高U盘传输文件的性能?
U盘使用时间久了,其传输复制文件速度就可能会变得有些慢.出现这个问题的原因有很多,除了U盘本身的问题外,也可能会有电脑设置方面的因素在影响.好系统下面就来告诉大家解决U盘传输复制文件速度慢的几个小技巧 ...
- 从 Android 源码到 apk 的编译打包流程
文中涉及到的工具所在目录:Android/sdk/build-tools.下面开始分解并逐步实现对源码的打包. 编译流程 1. 生成仅包含资源文件的 apk 包和 R.java 文件 根据资源文件和 ...
- markdown实现点击链接下载文件
今天用Markdown工具,需要实现一个点连接下载文件的功能,看起来很多简单我也没多想就直接写了,并且单个页面测试的时候也挺正常,就发布了,但是发布后使用的时候发现问题了,浏览器中直接点击链接没反应, ...