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. 猫哥网络编程系列:详解 BAT 面试题

    从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...

  2. ASP.NET Identity入门系列教程(一) 初识Identity

    摘要 通过本文你将了解ASP.NET身份验证机制,表单认证的基本流程,ASP.NET Membership的一些弊端以及ASP.NET Identity的主要优势. 目录 身份验证(Authentic ...

  3. delete

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. Atitit rss没落以及替代品在线阅读器

    Atitit rss没落以及替代品在线阅读器 1.1. 对RSS的疯狂追逐,在2005年达到了一个高峰.1 1.2. Rss的问题,支持支rss,不支持url1 1.3. ,博客受到社交网络的冲击.s ...

  5. Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结

    Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结 1. 验证码的前世今生11.1. 第一代验证码 图片验证码11.2. 第二代验证码  用户操作 ,比如 ...

  6. Sql Server系列:规范化及基本设计

    1 理解表 表是具有相同常规属性(attribute)的数据实例的集合.这些数据实例组成数据行和列. 2 数据表设计范式 2.1 第一范式 第一范式(1NF)是关于消除重复数据组和保证原子性的规范化. ...

  7. fluent-ffmpeg 常用函数

    最近项目频繁用到fluent-ffmpeg,将目前使用到的函数进行总结. 首先引入fluent-ffmpeg模块: var ffmpeg = require('fluent-ffmpeg'); 1.函 ...

  8. Runtime应用防止按钮连续点击 (转)

    好久之前就看到过使用Runtime解决按钮的连续点击的问题,一直觉得没啥好记录的.刚好今天旁边同时碰到这个问题,看他们好捉急而且好像很难处理,于是我先自己看看… 前面自己也学习了很多Runtime的东 ...

  9. CSS3与页面布局学习总结(六)——CSS3新特性(阴影、动画、渐变、变形、伪元素等)

    CSS3在CSS2.1的基础上新增加了许多属性,这里选择了较常用的一些功能与大家分享,帮助文档中有很详细的描述,可以在本文的示例中获得帮助文档. 一.阴影 1.1.文字阴影 text-shadow&l ...

  10. 监视EntityFramework中的sql流转你需要知道的三种方式Log,SqlServerProfile, EFProfile

    大家在学习entityframework的时候,都知道那linq写的叫一个爽,再也不用区分不同RDMS的sql版本差异了,但是呢,高效率带来了差灵活性,我们 无法控制sql的生成策略,所以必须不要让自 ...