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. .NET Core性能测试组件BenchmarkDotNet 支持.NET Framework Mono

    .NET Core 超强性能测试组件BenchmarkDotNet 支持Full .NET Framework, .NET Core (RTM), Mono. BenchmarkDotNet支持 C# ...

  2. 纯JS打造比QQ空间更强大的图片浏览器-支持拖拽、缩放、过滤、缩略图等

    在线演示地址(打开网页后,点击商家图册): http://www.sport7.cn/cc/jiangnan/football5.html 先看一看效果图: 该图片浏览器实现的功能如下: 1. 鼠标滚 ...

  3. what's deviceone

    DeviceOne技术介绍 一.     DeviceOne是什么 DeviceOne(以下简称Do)是一个移动开发的平台或技术,与之对等的是Android移动开发技术,iOS移动开发技术,Windo ...

  4. Leetcode 笔记 117 - Populating Next Right Pointers in Each Node II

    题目链接:Populating Next Right Pointers in Each Node II | LeetCode OJ Follow up for problem "Popula ...

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

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

  6. ABP源码分析三十四:ABP.Web.Mvc

    ABP.Web.Mvc模块主要完成两个任务: 第一,通过自定义的AbpController抽象基类封装ABP核心模块中的功能,以便利的方式提供给我们创建controller使用. 第二,一些常见的基础 ...

  7. linux笔记

    1 动态查看日志 tail -f filename tail -1000f filename 2 解压当前目录内容为xxx.zip  zip -r xxx.zip ./* 3 查看内存使用情况 fre ...

  8. 对百度的UEditor多图片上传的一些补充

    我已经写了一篇文章关于百度的UEditor提取多图片上传模块.如果还没有看过,请点击以下链接查看 http://www.cnblogs.com/luke1006/p/3719029.html 出差了两 ...

  9. Android开发学习之路-DiffUtil使用教程

    谷歌最近更新了Support Library 24.2.0,而DiffUtil就是在这个版本添加的一个工具类. DiffUtil是一个查找集合变化的工具类,是搭配RecyclerView一起使用的,如 ...

  10. CentOS 6.6 升级GCC G++ (当前最新版本为v6.1.0) (完整)

    ---恢复内容开始--- CentOS 6.6 升级GCC G++ (当前最新GCC/G++版本为v6.1.0) 没有便捷方式, yum update....   yum install 或者 添加y ...