1.排队机制

接收输入TCP报文时,有三个队列:

● 待处理队列

● 预排队队列

● 接收队列

接收队列包含了处理过的TCP数据段,也就是说,去除了全部的协议头,正准备将数据复制到用户应用程序。接收队列包含了所有按顺序接收的数据段,在其他两个队列中的TCP数据段则需要进一步处理。

TCP报文首先由tcp_v4_rcv()进行处理。该函数要决定是否需要处理报文或者在待处理队列和预排队队列中排队。

/* 传输层报文处理入口 */
int tcp_v4_rcv(struct sk_buff *skb)
{
...
/*首先获取一个套接字旋转锁,当进入该例程时,要禁用下半部功能,因为该
例程是从NET SoftIRQ中断调用的。*/
bh_lock_sock(sk);/* 在软中断中对套接口加锁 */
ret = 0;
/* 如果进程没有访问传输控制块,则进行正常接收 */
/*接着检查套接字是否处于使用状态。当有人在使用该套接字时,(sk)->sk_lock.owner
为1.当对套接字执行读、写、修改操作时,套接字就会处于使用状态。*/
if (!sock_owned_by_user(sk)) {
/*调用tcp_prequeue将该TCP报文发往预排队队列。*/
if (!tcp_prequeue(sk, skb))
/*如果无法将TCP排队,就直接处理该数据段。*/
ret = tcp_v4_do_rcv(sk, skb);
} else
/* 将报文添加到后备队列中,待用户进程解锁控制块时处理 */
sk_add_backlog(sk, skb);
bh_unlock_sock(sk);
...
}

2.tcp_rcv_established()的处理

这里不介绍全部处理细节,仅介绍处理和排队机制。首先讨论直接将数据复制到用户缓冲区的可能性。如果不可能,就去除TCP头,将数据段发往接收队列排队。

/* 当连接已经正常建立时,处理接收到的TCP报文 */
int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
struct tcp_sock *tp = tcp_sk(sk);
...
}
else {/* 有数据负荷 */
int eaten = 0; /* 判断正在接收的段是否可以直接复制到用户空间 */
/* 正在接收的段的序号是否与尚未从内核空间复制到用户空间的段最
前面的序号相等,即接收队列应当是空的 */
/* TCP段中的用户数据长度小于用户空间缓存的剩余可用量 */
if (tp->ucopy.task == current &&
tp->copied_seq == tp->rcv_nxt &&
len - tcp_header_len <= tp->ucopy.len &&
sock_owned_by_user(sk)) {/* 锁被当前进程持有 */
__set_current_state(TASK_RUNNING); /* 将SKB的数据复制到用户缓冲区 */
if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) { if (tcp_header_len ==
(sizeof(struct tcphdr) +
TCPOLEN_TSTAMP_ALIGNED) &&
tp->rcv_nxt == tp->rcv_wup)/* 更新时间戳 */
tcp_store_ts_recent(tp); tcp_rcv_rtt_measure_ts(tp, skb);/* 更新往返时间 */ __skb_pull(skb, tcp_header_len);
/* 下一个预期接收的段序号 */
/*将tp->rcv_nxt更新为已处理报文的结束序列号。*/
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
NET_INC_STATS_BH(LINUX_MIB_TCPHPHITSTOUSER);
eaten = 1;
}
}
if (!eaten) {
...
/* 移动指针,跳过TCP头部,也就是去除TCP头 */
__skb_pull(skb,tcp_header_len);
/* 将数据包添加到接收队列中缓存起来,等待进程主动读取 */
__skb_queue_tail(&sk->sk_receive_queue, skb);
/* 设置skb的属主为当前套口,更新使用的接收缓存总量及预分配缓存长度 */
sk_stream_set_owner_r(skb, sk);
/* 更新rcv_nxt为该分段的结束序列号 */
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
}
...
return 0;
}

3.

内容太多了,未完待续

Linux2.6内核协议栈系列--TCP协议2.接收的更多相关文章

  1. Linux2.6内核协议栈系列--TCP协议1.发送

    在介绍tcp发送函数之前得先介绍很关键的一个结构sk_buff,在linux中,sk_buff结构代表了一个报文: 然后见发送函数源码,这里不关注硬件支持的分散-聚集: /* sendmsg系统调用在 ...

  2. 网络编程--使用TCP协议发送接收数据

    package com.zhangxueliang.tcp; import java.io.IOException; import java.io.OutputStream; import java. ...

  3. Linux 内核协议栈之TCP连接关闭

    Close行为: 当应用程序在调用close()函数关闭TCP连接时,Linux内核的默认行为是将套接口发送队列里的原有数据(比如之前残留的数据)以及新加入 的数据(比如函数close()产生的FIN ...

  4. Linux2.6内核进程调度系列--scheduler_tick()函数1.总体思想

    参考的是ULK第三版,Linux2.6.11.12内核版本. 调度程序依靠几个函数来完成调度工作,其中最重要的第一个函数是scheduler_tick函数,主要步骤如下: /** * 维持当前最新的t ...

  5. 结合Wireshark捕获分组深入理解TCP/IP协议栈之TCP协议(TCP报文格式+三次握手实例)

    摘要:     本文简单介绍了TCP面向连接理论知识,详细讲述了TCP报文各个字段含义,并从Wireshark俘获分组中选取TCP连接建立相关报文段进行分析. 一.概述     TCP是面向连接的可靠 ...

  6. Linux2.6内核进程调度系列--scheduler_tick()函数3.更新普通进程的时间片

    RT /** * 运行到此,说明进程是普通进程.现在开始更新普通进程的时间片. */ /* 首先递减普通进程的时间片计数器.如果用完,继续执行以下操作 */ if (!--p->time_sli ...

  7. Linux2.6内核进程调度系列--scheduler_tick()函数2.更新实时进程的时间片

    RT /** * 递减当前进程的时间片计数器,并检查是否已经用完时间片. * 由于进程的调度类型不同,函数所执行的操作也有很大差别. */ /* 如果是实时进程,就进一步根据是FIFO还是RR类型的实 ...

  8. TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现

    题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...

  9. 渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(5)

    前情回顾:一篇短短的博客明显不能满足TCP和UDP这两个饥渴的汉子,而且还被应用协议占了一小半的篇幅.在昨天结束之后,相信大家都基本对TCP/IP协议栈的轮廓有一个大概的印象了,能够对整体有所把握. ...

随机推荐

  1. Openfire集群源码分析

    如果用户量增加后为了解决吞吐量问题,需要引入集群,在openfire中提供了集群的支持,另外也实现了两个集群插件:hazelcast和clustering.为了了解情况集群的工作原理,我就沿着open ...

  2. 斗天斗地斗控件 -- 与 Flyout 控件的斗争史

    前言 在淘宝的收藏夹页面本地化过程中,收藏的宝贝和店铺的分类展示通过一个下拉菜单的方式进行展示.如果单独为此从头重写一个控件,那么不但费时费力,包括所有的动画方式都要全新设计,而且还容易出 bug.好 ...

  3. 图形数据库Neo4J简介

    最近我在用图形数据库来完成对一个初创项目的支持.在使用过程中觉得这种图形数据库实际上挺有意思的.因此在这里给大家做一个简单的介绍. NoSQL数据库相信大家都听说过.它们常常可以用来处理传统的关系型数 ...

  4. 微信硬件H5面板开发(一) ---- 调用openApi

    微信硬件平台是微信推出连接物与人,物与物的IOT解决方案.也就是说可以通过微信控制各种智能设备.比如一些蓝牙设备.空调.电视等等. 我本身不懂硬件(虽然是电子信息专业),硬件是北航的两个研究生在弄,小 ...

  5. 让Unity NavMesh为我所用

    Unity里面整合了一个NavMesh功能,虽然让人又爱又恨. 但当你在其他地方需要这个NavMesh的数据时,就更让人欲罢不能了. 比如说服务器需要Unity的NavMesh数据时. 比如说你想将U ...

  6. ASP.NET Web API 开篇示例介绍

    ASP.NET Web API 开篇示例介绍 ASP.NET Web API 对于我这个初学者来说ASP.NET Web API这个框架很陌生又熟悉着. 陌生的是ASP.NET Web API是一个全 ...

  7. Go语言实战 - 使用SendCloud群发邮件

    山坡网需要能够每周给注册用户发送一封名为"本周最热书籍"的邮件,而之前一直使用的腾讯企业邮箱罢工了,提示说发送请求太多太密集. 一番寻找之后发现了大家口碑不错的搜狐SendClou ...

  8. Entity Framework 6 Recipes 2nd Edition(12-8)译 -> 重新获取一个属性的原始值

    12-8. 重新获取一个属性的原始值 问题 在实体保存到数据库之前,你想重新获取属性的原始值 解决方案 假设你有一个模型 (见 Figure 12-11) 表示一个员工( Employee),包含工资 ...

  9. 初学者--bootstrap(六)组件中的字体图标----在路上(9)

    组件---字体图标 无数可复用的组件,包括字体图标.下拉菜单.导航.警告框.弹出框等更多功能. 1.如何使用:        出于性能的考虑,所有图标都需要一个基类和对应每个图标的类.把下面的代码放在 ...

  10. 计数排序(counting-sort)——算法导论(9)

    1. 比较排序算法的下界 (1) 比较排序     到目前为止,我们已经介绍了几种能在O(nlgn)时间内排序n个数的算法:归并排序和堆排序达到了最坏情况下的上界:快速排序在平均情况下达到该上界.   ...