TCP输入 之 tcp_data_queue
tcp_data_queue作用为数据段的接收处理,其中分为多种情况:
(1) 无数据,释放skb,返回;
(2) 预期接收的数据段,a. 进行0窗口判断;b. 进程上下文,复制数据到用户空间;c. 不满足b或者b未完整拷贝此skb的数据段,则加入到接收队列;d. 更新下一个期望接收的序号;e. 若有fin标记,则处理fin;f. 乱序队列不为空,则处理乱序;g. 快速路径的检查和设置;h. 唤醒用户空间进程读取数据;
(3) 重传的数据段,进入快速ack模式,释放该skb;
(4) 窗口以外的数据段,进入快速ack模式,释放该skb;
(5) 数据段重叠,在进行0窗口判断之后,进行(2)中的加入接收队列,以及>=d的流程;
(6) 乱序的数据段,调用tcp_data_queue_ofo进行乱序数据段的接收处理;
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
bool fragstolen = false;
int eaten = -; /* 无数据 */
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
__kfree_skb(skb);
return;
} /* 删除路由缓存 */
skb_dst_drop(skb); /* 去掉tcp首部 */
__skb_pull(skb, tcp_hdr(skb)->doff * ); tcp_ecn_accept_cwr(tp, skb); tp->rx_opt.dsack = ; /* Queue data for delivery to the user.
* Packets in sequence go to the receive queue.
* Out of sequence packets to the out_of_order_queue.
*/
/* 预期接收的数据段 */
if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
/* 窗口为0,不能接收数据 */
if (tcp_receive_window(tp) == )
goto out_of_window; /* Ok. In sequence. In window. */
/* 进程上下文 */ /* 当前进程读取数据 */
if (tp->ucopy.task == current &&
/* 用户空间读取序号与接收序号一致&& 需要读取的数据不为0 */
tp->copied_seq == tp->rcv_nxt && tp->ucopy.len &&
/* 被用户空间锁定&& 无紧急数据 */
sock_owned_by_user(sk) && !tp->urg_data) { /* 带读取长度和数据段长度的较小值 */
int chunk = min_t(unsigned int, skb->len,
tp->ucopy.len);
/* 设置running状态 */
__set_current_state(TASK_RUNNING); /* 拷贝数据 */
if (!skb_copy_datagram_msg(skb, , tp->ucopy.msg, chunk)) {
tp->ucopy.len -= chunk;
tp->copied_seq += chunk;
/* 完整读取了该数据段 */
eaten = (chunk == skb->len); /* 调整接收缓存和窗口 */
tcp_rcv_space_adjust(sk);
}
} /* 未拷贝到用户空间或者未拷贝完整数据段 */
if (eaten <= ) {
queue_and_out:
/* 没有拷贝到用户空间,对内存进行检查 */
if (eaten < ) {
if (skb_queue_len(&sk->sk_receive_queue) == )
sk_forced_mem_schedule(sk, skb->truesize);
else if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
goto drop;
} /* 添加到接收队列 */
eaten = tcp_queue_rcv(sk, skb, , &fragstolen);
} /* 更新下一个期望接收的序号*/
tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
/* 有数据 */
if (skb->len)
tcp_event_data_recv(sk, skb); /* 标记有fin,则处理 */
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
tcp_fin(sk); /* 乱序队列有数据,则处理 */
if (!RB_EMPTY_ROOT(&tp->out_of_order_queue)) { /* 将乱序队列中的数据段转移到接收队列 */
tcp_ofo_queue(sk); /* RFC2581. 4.2. SHOULD send immediate ACK, when
* gap in queue is filled.
*/
/* 乱序数据段处理完毕,需要立即发送ack */
if (RB_EMPTY_ROOT(&tp->out_of_order_queue))
inet_csk(sk)->icsk_ack.pingpong = ;
} if (tp->rx_opt.num_sacks)
tcp_sack_remove(tp); /* 快路检查 */
tcp_fast_path_check(sk); /* 向用户空间拷贝了数据,则释放skb */
if (eaten > )
kfree_skb_partial(skb, fragstolen); /* 不在销毁状态,则唤醒进程读取数据 */
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk);
return;
} /* 重传 */
if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
/* A retransmit, 2nd most common case. Force an immediate ack. */
NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);
tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); out_of_window:
/* 进入快速ack模式 */
tcp_enter_quickack_mode(sk); /* 调度ack */
inet_csk_schedule_ack(sk);
drop:
/* 释放skb */
tcp_drop(sk, skb);
return;
} /* Out of window. F.e. zero window probe. */
/* 窗口以外的数据,比如零窗口探测报文段 */
if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp)))
goto out_of_window; /* 进入快速ack模式 */
tcp_enter_quickack_mode(sk); /* 数据段重叠 */
if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
/* Partial packet, seq < rcv_next < end_seq */
SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
TCP_SKB_CB(skb)->end_seq); tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, tp->rcv_nxt); /* If window is closed, drop tail of packet. But after
* remembering D-SACK for its head made in previous line.
*/
/* 窗口为0,不能接收 */
if (!tcp_receive_window(tp))
goto out_of_window;
goto queue_and_out;
} /* 接收乱序数据段 */
tcp_data_queue_ofo(sk, skb);
}
TCP输入 之 tcp_data_queue的更多相关文章
- TCP输入 之 tcp_rcv_established
概述 tcp_rcv_established用于处理已连接状态下的输入,处理过程根据首部预测字段分为快速路径和慢速路径: 1. 在快路中,对是有有数据负荷进行不同处理: (1) 若无数据,则处理输入a ...
- tcp 输入 简析 转载
正常来说 TCP 收消息过程会涉及三个队列: Backlog Queue sk->sk_backlog Prequeue tp->ucopy.prequeue Receive Queue ...
- TCP输入 之 快速路径和慢速路径
概述 快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的: 慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数 ...
- TCP输入 之 tcp_prequeue
在未开启tcp_low_latency的情况下,软中断将skb送上来,加入到prequeue中,然后 在未启用tcp_low_latency且有用户进程在读取数据的情况下,skb入队到prequeue ...
- TCP输入 之 tcp_v4_rcv
tcp_v4_rcv函数为TCP的总入口,数据包从IP层传递上来,进入该函数:其协议操作函数结构如下所示,其中handler即为IP层向TCP传递数据包的回调函数,设置为tcp_v4_rcv: sta ...
- tcp 输入 prequeue以及backlog队列
/*ipv4_specific是TCP传输层到网络层数据发送以及TCP建立过程的真正OPS, 在tcp_prot->init中被赋值给inet_connection_sock->icsk_ ...
- TCP输入 之 tcp_queue_rcv
tcp_queue_rcv用于将接收到的skb加入到接收队列receive_queue中,首先会调用tcp_try_coalesce进行分段合并到队列中最后一个skb的尝试,若失败则调用__skb_q ...
- 前端学HTTP之连接管理
前面的话 HTTP连接是HTTP报文传输的关键通道.要掌握HTTP就需要理解HTTP连接的来龙去脉以及如何使用这些连接 如果想查看一个网页,浏览器收到URL时,会执行下图所示的步骤.将服务器的IP地址 ...
- atitit.http原理与概论attilax总结
atitit.http原理与概论attilax总结 1. 图解HTTP 作者:[日]上野宣 著1 2. HTTP权威指南(国内首本HTTP及其相关核心Web技术权威著作)1 3. TCP/IP详解(中 ...
随机推荐
- O052、Create Volume 操作 (Part III)
参考https://www.cnblogs.com/CloudMan6/p/5617980.html Jun 20 17:15:56 DevStack-Rocky-Compute-22 c ...
- java 将一个正整数翻译成人民币大写的读法
程序如下: import java.lang.StringBuffer; /** 给定一个浮点数,将其装换成人民币大写的读法 88.5:捌十捌元零伍角 */ public class Num2Rmb ...
- 一步步创建第一个Vue项目
写在了GitHub https://github.com/TaoPanfeng/vue-cms 1 初始化 创建一个文件夹 vue-cms 在vue-cms目录下创建文件 package.json 在 ...
- 基于MQTT的串口数据转发器
问: ComHub能做什么?ComHub使用MQTT协议,将串口数据经TCP分发出去.这种结构可以实现很多功能:1.COM-Over-TCP: 将COM数据使用TCP远程传送;2.COM多播:一个CO ...
- ADO.net 数据库连接new SqlConnection、Open、Close、Dispose
今天踩了一个坑,用了一个static对象,存储了Connection,导致了并发量大时(35/s)出现单个连接的数据库请求堆积,以及并发Open导致的异常,最终使服务下线. 排查中发现有些概念不清的地 ...
- svn+jenkins自动部署
需求:项目经理想要将原型图修改完后直接发布 前置条件: 已经有了svn服务器,并正常使用 已经有了jenkins服务器,之前搭建的gitlab+jenkins, 如需搭建jenkins,参考 http ...
- 无聊开始玩路由器,入门Tomato固件
无聊开始玩路由器,入门Tomato固件 在Wordpress上消失了一段时间,其实我最近几个月都比较宅.相信最近大家都了解过新出的一款很NB的路由器叫极路由,功能很强大,8G的可存储空间,可以安装路由 ...
- Java SE 核心 II【Collection 集合框架】
Collection集合框架 在实际开发中,需要将使用的对象存储于特定数据结构的容器中.而 JDK 提供了这样的容器——集合框架,集合框架中包含了一系列不同数据结构(线性表.查找表)的实现类.集合的引 ...
- mysql数据库:数据类型、存储引擎、约束、
1.详细的建表语句 ***** create table 表名( 字段名 数据类型[(长度) 约束条件] ); []代表可选的 为什么需要给数据分类? 189 一 ...
- 【XDOJ】小W的塔防
原题: 小W在成功拿到iPhone后,下载了一个塔防游戏.游戏的目标是阻止僵尸穿过地图. 地图可以看作一条长度为n的线段,这条线段被划分为n条单位长度的小线段.僵尸需要花费t秒才能通过一条小线段.在每 ...