一、tcp_transmit_skb

static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
gfp_t gfp_mask)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct inet_sock *inet;
struct tcp_sock *tp;
struct tcp_skb_cb *tcb;
struct tcp_out_options opts;
unsigned tcp_options_size, tcp_header_size;
struct tcp_md5sig_key *md5;
struct tcphdr *th;
int err; BUG_ON(!skb || !tcp_skb_pcount(skb)); /* If congestion control is doing timestamping, we must
* take such a timestamp before we potentially clone/copy.
*/
/*如果拥塞控制需要做时间才有,则必须在克隆或者拷贝报文之前设置一个时间戳。
linux支持了多达十种拥塞控制算法,但并不是每种算中都需要做时间采样的,
因此在设置时间戳前先判断当前的拥塞算法是否需要做时间采样。*/
if (icsk->icsk_ca_ops->flags & TCP_CONG_RTT_STAMP)
__net_timestamp(skb); /*根据传递进来的clone_it参数来确定是否需要克隆待发送的报文。*/
if (likely(clone_it)) {
/*如果skb已经被clone,则只能复制该skb的数据到新分配的skb中*/
if (unlikely(skb_cloned(skb)))
skb = pskb_copy(skb, gfp_mask);
else
/*clone新的skb*/
skb = skb_clone(skb, gfp_mask);
if (unlikely(!skb))
return -ENOBUFS;
} /*获取INET层和TCP层的传输控制块、skb中的TCP私有数据块。*/
inet = inet_sk(sk);
tp = tcp_sk(sk);
tcb = TCP_SKB_CB(skb);
memset(&opts, 0, sizeof(opts)); /*根据TCP选项重新调整TCP首部的长度。*/
/*判断当前TCP报文是否是SYN段,因为有些选项只能出现在SYN报文中,需做特别处理。*/
if (unlikely(tcb->flags & TCPHDR_SYN))
tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5);
else
tcp_options_size = tcp_established_options(sk, skb, &opts, &md5); /*tcp首部的总长度等于可选长度加上struct tcphdr。*/
tcp_header_size = tcp_options_size + sizeof(struct tcphdr); /*如果已发出但未确认的数据包数目为零,则只初始化拥塞控制,并开始跟踪该连接的RTT。*/
if (tcp_packets_in_flight(tp) == 0)
tcp_ca_event(sk, CA_EVENT_TX_START); /*调用skb_push()在数据部分的头部添加TCP首部,长度即为之前计算得到的那个tcp_header_size,实际上是把data指针往上移。*/
skb_push(skb, tcp_header_size);
skb_reset_transport_header(skb);
/*SKB已添加到发送队列中,但是从SKB的角度去看还不知道他是属于哪个传输控制块,因此调用skb_set_owner_w设置该SKB的宿主。*/
skb_set_owner_w(skb, sk); /* Build TCP header and checksum it. */
/*填充TCP首部中的源端口source、目的端口dest、TCP报文的序号seq、确认序号ack_seq以及各个标志位*/
th = tcp_hdr(skb);
th->source = inet->inet_sport;
th->dest = inet->inet_dport;
th->seq = htonl(tcb->seq);
th->ack_seq = htonl(tp->rcv_nxt);
*(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
tcb->flags); /*分两种情况设置TCP首部的接收窗口的大小*/
if (unlikely(tcb->flags & TCPHDR_SYN)) {
/* RFC1323: The window in SYN & SYN/ACK segments
* is never scaled.
*/
/*如果是SYN段,则设置接收窗口初始值为rcv_wnd*/
th->window = htons(min(tp->rcv_wnd, 65535U));
} else {
/*如果是其他的报文,则调用tcp_select_window()计算当前接收窗口的大小。*/
th->window = htons(tcp_select_window(sk));
}
/*初始化TCP首部的校验码和紧急指针,具体请参考TCP协议中的首部定义。*/
th->check = 0;
th->urg_ptr = 0; /* The urg_mode check is necessary during a below snd_una win probe */
if (unlikely(tcp_urg_mode(tp) && before(tcb->seq, tp->snd_up))) {
if (before(tp->snd_up, tcb->seq + 0x10000)) {
th->urg_ptr = htons(tp->snd_up - tcb->seq);
th->urg = 1;
} else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) {
th->urg_ptr = htons(0xFFFF);
th->urg = 1;
}
} tcp_options_write((__be32 *)(th + 1), tp, &opts);
if (likely((tcb->flags & TCPHDR_SYN) == 0))
TCP_ECN_send(sk, skb, tcp_header_size); #ifdef CONFIG_TCP_MD5SIG
/* Calculate the MD5 hash, as we have all we need now */
if (md5) {
sk_nocaps_add(sk, NETIF_F_GSO_MASK);
tp->af_specific->calc_md5_hash(opts.hash_location,
md5, sk, NULL, skb);
}
#endif icsk->icsk_af_ops->send_check(sk, skb); if (likely(tcb->flags & TCPHDR_ACK))
tcp_event_ack_sent(sk, tcp_skb_pcount(skb)); if (skb->len != tcp_header_size)
tcp_event_data_sent(tp, skb, sk); if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS,
tcp_skb_pcount(skb));
/*调用发送接口queue_xmit发送报文,进入到ip层,如果失败返回错误码。在TCP中该接口实现函数为ip_queue_xmit()*/
err = icsk->icsk_af_ops->queue_xmit(skb);
if (likely(err <= 0))
return err; tcp_enter_cwr(sk, 1); return net_xmit_eval(err);
}

from:http://sunjiangang.blog.chinaunix.net/uid-9543173-id-3560665.html

TCP发送源码学习(3)--tcp_transmit_skb的更多相关文章

  1. TCP发送源码学习(1)--tcp_sendmsg

    一.tcp_sendmsg()函数分析: int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t ...

  2. TCP发送源码学习(2)--tcp_write_xmit

    一.tcp_write_xmit()将发送队列上的SBK发送出去,返回值为0表示发送成功.函数执行过程如下:1.检测拥塞窗口的大小.2.检测当前报文是否完全处在发送窗口内.3.检测报文是否使用nagl ...

  3. RocketMQ 源码学习笔记————Producer 是怎么将消息发送至 Broker 的?

    目录 RocketMQ 源码学习笔记----Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest ...

  4. RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?

    目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest Roc ...

  5. Netty 源码学习——EventLoop

    Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

  7. igmpproxy源码学习——igmpProxyInit()

    igmpproxy源码学习--igmpProxyInit()函数具体解释.igmpproxy初始化 在执行igmpproxy的主程序igmpproxyRun()之前须要对igmpproxy进行一些配置 ...

  8. 源码学习之ASP.NET MVC Application Using Entity Framework

    源码学习的重要性,再一次让人信服. ASP.NET MVC Application Using Entity Framework Code First 做MVC已经有段时间了,但看了一些CodePle ...

  9. 【Spark2.0源码学习】-1.概述

          Spark作为当前主流的分布式计算框架,其高效性.通用性.易用性使其得到广泛的关注,本系列博客不会介绍其原理.安装与使用相关知识,将会从源码角度进行深度分析,理解其背后的设计精髓,以便后续 ...

随机推荐

  1. Temple Build~dp(01背包的变形)

    The Dwarves of Middle Earth are renowned for their delving and smithy ability, but they are also mas ...

  2. mysql sql语句执行时是否使用索引检查方法

    在日常开发中,使用到的数据表经常都会有索引,这些索引可能是开发人员/DBA建表时创建的,也可能是在使用过程中新增的.合理的使用索引,可以加快数据库查询速度.然而,在实际开发工作中,会出现有些sql语句 ...

  3. [LeetCode] Second Minimum Node In a Binary Tree 二叉树中第二小的结点

    Given a non-empty special binary tree consisting of nodes with the non-negative value, where each no ...

  4. pyqt5 动画学习(一) 改变控件大小

    入坑pyqt也有半年了,由于人们对事物的审美,静态界面已经不能满足用户,而动画却给人眼前一亮,so,今天来学习pyqt的动画了 由于资料真的是太少,本人也是有啃外国佬的英文进行摸索学习,可能也是触及皮 ...

  5. python--元祖和字典

    一.1:元祖:tuple  在python中,元祖也是一个list, 它和list的区别是list中的元素可以修改,而元祖中的元素不可以修改. 2:元祖的定义:用小括号() 二.1.字典  字典全程d ...

  6. scrapy下载图片到自己的目录,创建缩略图,存储入库

    环境和工具:python2.7,scrapy 实验网站:http://www.27270.com/tag/333.html  爬去所有兔女郎图片,下面的推荐需要过滤 逻辑:分析网站信息,下载图片和入库 ...

  7. PHPCMS v9.6.0 任意用户密码重置

    参考来源:http://wooyun.jozxing.cc/static/bugs/wooyun-2016-0173130.html 他分析的好像不对.我用我的在分析一次. 先来看poc: /inde ...

  8. [ZJOI 2006]书架

    Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下 ...

  9. bzoj 1272: [BeiJingWc2008]Gate Of Babylon

    Description Solution 如果没有限制,答案就是 \(\sum_{i=0}^{m}C(n+i-1,i)\) 表示枚举每一次取的个数,且不超过 \(m\),方案数为可重组合 发现这个东西 ...

  10. 【bzoj4568 scoi2016】幸运数字

    题目描述 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征. 一些旅行者希望 ...