Linux 内核网络协议栈 ------ tcp重传数据包 tcp_retransmit_skb 函数_tcp协议栈 重传有关的函数-程序员宅基地

技术标签: linux  TCPIP  内核  Linux 内核之网络协议栈  网络协议  


/* This retransmits one SKB.  Policy decisions and retransmit queue
 * state updates are done by the caller.  Returns non-zero if an
 * error occurred which prevented the send.
 */
int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
         struct tcp_sock *tp = tcp_sk(sk);
         struct inet_connection_sock *icsk = inet_csk(sk);
         unsigned int cur_mss = tcp_current_mss(sk, 0);
         int err;
 
         /* Inconslusive MTU probe */
         if (icsk->icsk_mtup.probe_size) {
                 icsk->icsk_mtup.probe_size = 0;
         }
 
         /* Do not sent more than we queued. 1/4 is reserved for possible  
          * copying overhead: fragmentation, tunneling, mangling etc.
          */ // 如果消耗很多的内存做其他事,那么就没有多余的来做队列的处理了~
         if (atomic_read(&sk->sk_wmem_alloc) >                                     // sk_wmem_alloc:传输队列大小
             min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf))   // sk_wmem_queud:固定的队列大小
                 return -EAGAIN;
 
         if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {// 若这样,说明是有一部分数据才需要重传,形如:seq---snd_una---end_seq,前面一半已收到ACK
                 if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))  // 若这样,说明全部ACK,无需重传,BUG
                         BUG();
                 if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))  // 一些控制信息检查
                         return -ENOMEM;
         }
 
         /* If receiver has shrunk his window, and skb is out of
          * new window, do not retransmit it. The exception is the
          * case, when window is shrunk to zero. In this case
          * our retransmit serves as a zero window probe.
          */
         if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp))    // 如果数据在窗口后面,不会发送
             && TCP_SKB_CB(skb)->seq != tp->snd_una)   
                return -EAGAIN;
 
         if (skb->len > cur_mss) {   // 如果skb长度 > MSS
                 if (tcp_fragment(sk, skb, cur_mss, cur_mss))   // 先分片。再传送
                         return -ENOMEM; /* We'll try again later. */
         }
 
         /* Collapse two adjacent packets if worthwhile and we can. */  // 我*,这么多条件
         if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&              // SYN包
             (skb->len < (cur_mss >> 1)) &&                             // 长度<半个MSS
             (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) &&    // 不是结尾
             (!tcp_skb_is_last(sk, skb)) &&                             // 不是最后一个
             (skb_shinfo(skb)->nr_frags == 0 &&                         // 没有分页数据
              skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) &&
             (tcp_skb_pcount(skb) == 1 &&                               // gso_segs=1
              tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) &&
             (sysctl_tcp_retrans_collapse != 0))
                 tcp_retrans_try_collapse(sk, skb, cur_mss);            // 这个函数不是很明白,待看~~~~~~~~~~~~~~~~~~~~~~~~~
 
         if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) // 根据目的地址等条件获取路由,如果获取路由失败就不能发送
                 return -EHOSTUNREACH; /* Routing failure or similar. */
 
         /* Some Solaris stacks overoptimize and ignore the FIN on a
          * retransmit when old data is attached.  So strip it off
          * since it is cheap to do so and saves bytes on the network.
          *///Solaris系统的协议栈有时候会忽略重传SKB上带有的FIN标志的payload,将payload全部剥离掉,节省网络流量
         if (skb->len > 0 &&
             (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
             tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
                 if (!pskb_trim(skb, 0)) {
                         /* Reuse, even though it does some unnecessary work */
                         tcp_init_nondata_skb(skb, TCP_SKB_CB(skb)->end_seq - 1,
                                              TCP_SKB_CB(skb)->flags);
                         skb->ip_summed = CHECKSUM_NONE;
                 }
         }
 
         /* Make a copy, if the first transmission SKB clone we made
          * is still in somebody's hands, else make a clone.
          */
         TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
         err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);    // 这个才是正在的传输函数~~~~~~~~~~~~~~~~~~~~后面再说~~~~~~~~~~~~~~~
                                                            // 这个函数就是将数据包发送到下面一层,再慢慢传输出去~~~~~~~~~~~~~~
         if (err == 0) {    // 发送成功,那么就需要更新TCP统计信息
                 /* Update global TCP statistics. */  
                 TCP_INC_STATS(TCP_MIB_RETRANSSEGS);
 
                 tp->total_retrans++;   // 整体重传数量++
 
#if FASTRETRANS_DEBUG > 0
                 if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
                         if (net_ratelimit())
                                 printk(KERN_DEBUG "retrans_out leaked.\n");
                 }
#endif
                 if (!tp->retrans_out)
                         tp->lost_retrans_low = tp->snd_nxt;
                 TCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS;
                 tp->retrans_out += tcp_skb_pcount(skb);   // 重传出去的数量+=。。。
 
                 /* Save stamp of the first retransmit. */
                 if (!tp->retrans_stamp)
                         tp->retrans_stamp = TCP_SKB_CB(skb)->when;  // 第一次重传时间戳
 
                 tp->undo_retrans++;
 
                 /* snd_nxt is stored to detect loss of retransmitted segment,
                  * see tcp_input.c tcp_sacktag_write_queue().
                  */
                 TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt;
         }
         return err;
}
 



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/shanshanpt/article/details/22202999

智能推荐

【九度】题目1090:路径打印 && 【LeetCode】Simplify Path_打印目录结构 leetcode-程序员宅基地

文章浏览阅读1.3k次。1、题目1090:路径打印时间限制:1 秒内存限制:32 兆特殊判题:否提交:1319解决:230题目描述:给你一串路径,譬如:a\b\ca\d\eb\cstd\你把这些路径中蕴含的目录结构给画出来,子目录直接列在父目录下面,并比父目录向右缩一格,就像这样:a b c d eb cstd同一级的需要按字母顺序_打印目录结构 leetcode

如何使用Cordova将SAP Fiori应用打包并安装到Android平台上_fiori发布安卓-程序员宅基地

文章浏览阅读591次。There is a wonderful tutorial Building SAP Fiori-like UIs with SAPUI5 in 10 Exercises written by Bertram Ganz.In this blog, I will show step by step how to package the UI5 application built by this tutorial as a native application into your Android device_fiori发布安卓

程序员代码面试指南下(7-9)-程序员宅基地

文章浏览阅读182次。目录第7章 1 不用额外变量交换两个整数的值(士 ★☆☆☆) 2 不用任何比较判断找出两个数中较大的数(校★★★☆) 3 只用位运算不用算术运算实现整数的加减乘除运算 4 整数的二进制表达中有多少个1 5 在其他数都出现偶数次的数组中找到出现奇数次的数 6 在其他数都出现A次的数组中找到只出现一次的数第8章 1 转圈打印矩阵 2 将正方形矩阵顺时针转动90度 3 之..._if (map.containskey(xor)) { int pre = map.get(xor); mosts[i] = pre =

uva-1399 Puzzle-程序员宅基地

文章浏览阅读152次。AC自动机上的dp

C++中 sprintf函数的用法_sprintf %c-程序员宅基地

文章浏览阅读871次。C++中 sprintf函数的用法1.常用方式sprintf函数的功能与printf函数的功能基本一样,只是它把结果输出到指定的字符串中了,看个例子就明白了:例:将”test 1 2”写入数组s中#include&lt;stdio.h&gt;int main(int argc, char *avgv[]){ char s[40]; sprintf(s,"%s%d..._sprintf %c

Java开发的医院门诊挂号系统_医院预约挂号er图-程序员宅基地

文章浏览阅读2.2k次。医院门诊系统,挂号预约系统,有四个角色(管理员,医生,护士,普通用户)_医院预约挂号er图

随便推点

Android Socket Demo [ 附客户端与服务端源码 ]_android socket客户端下载-程序员宅基地

文章浏览阅读818次。如果要跑通demo首先: 服务端我是用 intellij idea 开发的。如果用其他软件打跑不起来就用 intellij其次: 要将手机跟电脑连在同个网络下最后: Constants的ip地址要填写上电脑的ip地址实现功能:客户端连接服务端,客户端发数据到服务端,客户端收到服务端发来的数据服务端收到客户端发的数据,服务端发数据给客户端贴部分核心代码客户端连接服务端:首先客户端连接服务端必须要在线程里(后面的是 ip地址 跟端口,端口是服务端的socke..._android socket客户端下载

定制win10桌面_win10联想 自带主题-程序员宅基地

文章浏览阅读1.3k次,点赞4次,收藏7次。壁纸在文末先上几张美化后的照片 主题链接win 10 美化相信很多人都厌倦了win10原装主题了,陈旧的窗口边框,一如既往的图标,老掉牙的窗口样式和菜单栏……算了,就不吐槽了,直接上教程吧!前方高能第零步关掉杀毒软件(新手建议卸载),这点非常重要,如某数字,某讯,某霸,如果关掉以后放心不下自己电脑的安全,以下文章请勿食用!(后果自负)第一步破解原装win10系统主题。友..._win10联想 自带主题

jQuery懒加载插件 – jquery.lazyload.js简单调用-程序员宅基地

文章浏览阅读57次。 Lazy Load 是一个用 JavaScript 编写的 jQuery 插件. 它可以延迟加载长页面中的图片. 在浏览器可视区域外的图片不会被载入, 直到用户将页面滚动到它们所在的位置. 这与图片预加载的处理方式正好是相反的.在包含很多大图片长页面中延迟加载图片可以加快页面加载速度. 浏览器将会在加载可见图片之后即进入就绪状态. 在某些情况下还可以帮助降低服务器负担。一、下载和引用  ..._jq.lazyload.js配置

mysql_172.25.2.1-程序员宅基地

文章浏览阅读404次。一.cmake升级https://cmake.org/download/ #cmake下载地址 yum install jsoncpp-0.10.5-2.el7.x86_64.rpm jsoncpp-devel-0.10.5-2.el7.x86_64.rpm -y yum install cmake3-3.6.1-2.el7.x86_64.rpm cmake3-data-3.6.1-2.el7.noarch.rpm -y二.mysql编译安装升级gcctar zxf mysql-boost-_172.25.2.1

基于Numpy的线性代数运算_numpy线性代数运算-程序员宅基地

文章浏览阅读737次。标题中的英文首字母大写比较规范,但在python实际使用中均为小写。1.Numpy中的matrix1.1 创建matrix对象numpy.matrix方法的参数可以为ndarray对象numpy.matrix方法的参数也可以为字符串str,示例如下:import numpy as npm = np.matrix("1 2 3;4 5 6; 7 ..._numpy线性代数运算

搭建LAMP环境(源码方式)_this software is subject to the php license, avail-程序员宅基地

文章浏览阅读3.7k次。源码方式,搭建LAMP环境。_this software is subject to the php license, available in this | | distribut

推荐文章

热门文章

相关标签