概述

tcp_write_xmit函数完成对待发送数据的分段发送,过程中会遍历发送队列,进行窗口检查,需要TSO分段则分段,然后调用tcp_transmit_skb发送数据段;

源码分析
 static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
int push_one, gfp_t gfp)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
unsigned int tso_segs, sent_pkts;
int cwnd_quota;
int result;
bool is_cwnd_limited = false, is_rwnd_limited = false;
u32 max_segs; /* 已发送数据段数量 */
sent_pkts = ; /* 发送多个数据段 */
if (!push_one) {
/* Do MTU probing. */
/* 发送路径mtu探测 */
result = tcp_mtu_probe(sk);
/* 失败 */
if (!result) {
return false;
}
/* 成功,设置已发送数据段数为1 */
else if (result > ) {
sent_pkts = ;
}
} /* 获取最大tso分段 */
max_segs = tcp_tso_segs(sk, mss_now); /* 有数据段要发送 */
while ((skb = tcp_send_head(sk))) {
unsigned int limit; /* 初始化tso分段相关 */
tso_segs = tcp_init_tso_segs(skb, mss_now);
BUG_ON(!tso_segs); if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) {
/* "skb_mstamp" is used as a start point for the retransmit timer */
skb_mstamp_get(&skb->skb_mstamp);
goto repair; /* Skip network transmission */
} /* 检测拥塞窗口大小 */
cwnd_quota = tcp_cwnd_test(tp, skb);
/* 为0 */
if (!cwnd_quota) {
/* 尾部丢失探测段,设置为1 */
if (push_one == )
/* Force out a loss probe pkt. */
cwnd_quota = ;
/* 其他情况,跳出 */
else
break;
} /* 检查tcp的数据段是否在发送窗口之内 */
if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now))) {
/* 不在,标记,跳出 */
is_rwnd_limited = true;
break;
} /* 不需要tso分段 */
if (tso_segs == ) {
/* 检查nagle算法是否允许发送数据段 */
if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
(tcp_skb_is_last(sk, skb) ?
nonagle : TCP_NAGLE_PUSH))))
break;
}
/* 需要tso分段 */
else {
/* 检查是否可以延迟发送 */
if (!push_one &&
tcp_tso_should_defer(sk, skb, &is_cwnd_limited,
max_segs))
break;
} /* 设置分段长度限制为mss */
limit = mss_now; /* 需要分段 && 非紧急模式,重新确定分段长度限制 */
if (tso_segs > && !tcp_urg_mode(tp))
limit = tcp_mss_split_point(sk, skb, mss_now,
min_t(unsigned int,
cwnd_quota,
max_segs),
nonagle); /* skb中数据段长度>分段长度限制,则进行分段,会申请新的skb */
if (skb->len > limit &&
unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
break; if (test_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags))
clear_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags);
if (tcp_small_queue_check(sk, skb, ))
break; /* 发送分段数据 */
if (unlikely(tcp_transmit_skb(sk, skb, , gfp)))
break; repair:
/* Advance the send_head. This one is sent out.
* This call will increment packets_out.
*/
/* 进行发送之后的数据更新,包括统计计数和定时器等 */
tcp_event_new_data_sent(sk, skb); /* 更新最新发送小包的结束序号 */
tcp_minshall_update(tp, mss_now, skb); /* 更新发送数据段数量 */
sent_pkts += tcp_skb_pcount(skb); /* 只发送一个段,则跳出 */
if (push_one)
break;
} if (is_rwnd_limited)
tcp_chrono_start(sk, TCP_CHRONO_RWND_LIMITED);
else
tcp_chrono_stop(sk, TCP_CHRONO_RWND_LIMITED); /* 本次有数据发送,拥塞相关数据更新 */
if (likely(sent_pkts)) {
if (tcp_in_cwnd_reduction(sk))
tp->prr_out += sent_pkts; /* Send one loss probe per tail loss episode. */
/* 每次发送一个尾部丢失探测 */
if (push_one != )
tcp_schedule_loss_probe(sk); /* 拥塞窗口校验 */
is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd);
tcp_cwnd_validate(sk, is_cwnd_limited);
return false;
} /* 本次无数据发送,已发出未确认的数据段不为0或者发送队列为空,认为成功 */
return !tp->packets_out && tcp_send_head(sk);
}

TCP输出 之 tcp_write_xmit的更多相关文章

  1. 传输层(3)-缓冲区大小及限制、TCP输出

    3.缓冲区大小及限制 影响IP数据报大小的限制. 1)IPv4数据报,最大大小是65535. 2)硬件规定的MTU.以太网的MTU是1500字节.SLIP链路1006字节或296字节 3)路径MTU. ...

  2. UNIX网络编程——TCP输出,UDP输出

    TCP输出 每一个TCP套接字有一个发送缓冲区,我们可以使用SO_SNDBUF套接字选项来更改该缓冲区的大小.当某个应用进程调用write时,内核从该应用进程的缓冲区中复制所有数据到(或是应用程序的缓 ...

  3. TCP输出和UDP输出

    一.TCP输出 1)对端必须确认收到的数据,伴随来自对端的ACK的不断到达,本端TCP至此才能从套接字发送缓冲区中丢弃 已确认的数据:TCP必须为已发送的数据保留一个副本,直到它被对端确认为止 2)每 ...

  4. UNIX网络编程读书笔记:TCP输出、UDP输出和SCTP输出

    TCP输出 下图展示了应用进程写数据到TCP套接口的过程. 每一个TCP套接口有一个发送缓冲区,我们可以用SO_SNDBUF套接口选项来改变这个缓冲区的大小. 当应用进程调用write时,内核从应用进 ...

  5. logstash tcp multihost output(多目标主机输出,保证TCP输出链路的稳定性)

    在清洗日志时,有一个应用场景,就是TCP输出时,须要在一个主机挂了的情况下,自已切换到下一个可用入口.而原tcp output仅支持单个目标主机设定.故本人在原tcp的基础上,开发出tcp_multi ...

  6. TCP输出 之 tcp_transmit_skb

    概述 tcp_transmit_skb的作用是复制或者拷贝skb,构造skb中的tcp首部,并将调用网络层的发送函数发送skb:在发送前,首先需要克隆或者复制skb,因为在成功发送到网络设备之后,sk ...

  7. UNP——第二章,端口号,套接字对,TCP,UDP输出

    1.端口号 端口号用于区分使用相同协议的进程. TCP69 与 UDP69 是不同的. 端口号范围 0 - 65535, 其中 0- 1023 是保留端口. 2.套接字对 TCP服务通过套接字对,唯一 ...

  8. linux tcp Nagle算法,TCP_NODELAY和TCP_CORK 转载

    转载自: http://www.cnhalo.net/2016/08/13/linux-tcp-nagle-cork/ http://abcdxyzk.github.io/blog/2018/07/0 ...

  9. TCP/IP详解 (转)

    TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中 ...

随机推荐

  1. springboot 自动装配

    以下内容部分来自小马哥的 <springboot 编程思想> 基础 springboot 项目 maven 依赖 <dependency> <groupId>org ...

  2. ubuntu python3.5升级3.6后打不开终端的解决办法

    ubuntu python3.5升级3.6后打不开终端了. 解决办法如下: 1.Ctrl+Alt+F1进入命令行终端,我的电脑按Ctrl+Alt+F1没反应,按住Ctrl+Alt然后从F1到F5一个个 ...

  3. 高性能SQLServer分页语句

    第一种方法:效率最高 SELECT TOP 页大小 * FROM( SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1  ...

  4. Bmake

    Bmake is a common makefile framework. Both support native build and cross build. Easy for use, modif ...

  5. deep_learning_Function_sklearn.preprocessing.LabelBinarizer()

    在多数的机器学习比赛中,给出的标签都是非数字化的,所以我们需要对其进行转换.代码如下: from sklearn import preprocessing feature = [[0,1], [1,1 ...

  6. 修改虚拟机CentOS系统ip地址和主机名

    按照教程安装了虚拟机但是未配置静态IP,所以导致IP地址经常变化,CRT,mysql等连接时经常出现问题. 所以修改虚拟机内CentOS系统的IP为静态IP. 一.查看当前网关 虚拟机-->[编 ...

  7. Selenium(6)

    一.定位页面元素 1.高级定位:层级定位 思路:先定位到祖先节点,在定位该祖先节点范围内的子节点 2.高级定位:Xpath定位(重点) (1)Xpath定位:Xpath就是一个表达式,表示元素的路径, ...

  8. QTP(14)

    练习1.Flight4a 要求: a.录制Flight4a登录+退出业务流程 b.使用自定义检查结合Exist属性验证登录是否成功 c.为用户名实现参数化 用户名 Jack 正确 Rose 正确 12 ...

  9. 开源框架相关面试问题-okhttp网络框架面试问题详解

    OkHttp使用简介: ①.准备OkHttpClient对象: 一般app中使用网络可以全部用它,可以将它弄为全局变量,这样就可以共用它的缓存和线程池了. ②.准备Request对象: 很显然它是采用 ...

  10. 51Nod 1714 1位数SG异或打表

    SG[i]表示一个数二进制下有i个1的SG值 SG[0]=0 打表: #include<bits/stdc++.h> using namespace std; ]; ]; , x; int ...