lwip tcp_output_segment源码解析

本文深入探讨了TCP报文发送过程,从构建报文头部到实际发送至IP层的各个环节,包括设置ACK编号、通告窗口大小、处理选项、设置重传定时器等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原型:

static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)

功能:被tcp_output()调用来 发送TCP报文给IP层

实现:


源码如下:

/**
 * Called by tcp_output() to actually send a TCP segment over IP.被tcp_output()调用,实际的发送TCP报文给IP层
 *
 * @param seg the tcp_seg to send
 * @param pcb the tcp_pcb for the TCP connection used to send the segment
 */
static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
{
  u16_t len;
  struct netif *netif;
  u32_t *opts;

  /** @bug Exclude retransmitted segments from this count. */
  snmp_inc_tcpoutsegs();

  /* The TCP header has already been constructed, but the ackno and
   wnd fields remain.==TCP报头已经构建,但ackno和wnd字段需要保存 */
  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);

  /* advertise our receive window size in this TCP segment==在这个报文段中将要向对方通告我们接受窗口允许大小 */
  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
  /*更新rcv_ann_right_edge 上一次窗口通告时,窗口的右边缘值==rcv_nxt(下一个期望接收到的字节序号)+rcv_ann_wnd*/
  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;

  /* Add any requested options.  NB MSS option is only set on SYN
     packets, so ignore it here --MSS选项只当SYN包中设置,所以不再seg结构中体现*/
  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
  opts = (u32_t *)(void *)(seg->tcphdr + 1);/*+1 为sizeof(*(seg->tcphdr))*/
  if (seg->flags & TF_SEG_OPTS_MSS) {
    TCP_BUILD_MSS_OPTION(*opts);//MSS选项
    opts += 1;//u32
  }
#if LWIP_TCP_TIMESTAMPS
  pcb->ts_lastacksent = pcb->rcv_nxt;

  if (seg->flags & TF_SEG_OPTS_TS) {
    tcp_build_timestamp_option(pcb, opts);
    opts += 3;
  }
#endif

  /* Set retransmission timer running if it is not currently enabled 
     This must be set before checking the route.设置重传定时器使能,必须在检查route前设置 */
  if (pcb->rtime == -1) {
    pcb->rtime = 0;
  }

  /* If we don't have a local IP address, we get one by
     calling ip_route().==没有本地IP,获取一个 */
  if (ip_addr_isany(&(pcb->local_ip))) {
    netif = ip_route(&(pcb->remote_ip));
    if (netif == NULL) {
      return;
    }
    ip_addr_copy(pcb->local_ip, netif->ip_addr);
  }

  if (pcb->rttest == 0) {/*如果要求进行往返时间的估算,初始化相关参数*/
    pcb->rttest = tcp_ticks;//RRT估值时,以500ms周期递增
    pcb->rtseq = ntohl(seg->tcphdr->seqno);//用于测试RRT报文段序号

    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
  }
  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
          seg->len));
  /*调整报文段pbuf的payload指针,使他指向报文首部*/
  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);

  seg->p->len -= len;
  seg->p->tot_len -= len;

  seg->p->payload = seg->tcphdr;

  seg->tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
#if TCP_CHECKSUM_ON_COPY
  {
    u32_t acc;
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
    u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
           &(pcb->remote_ip),
           IP_PROTO_TCP, seg->p->tot_len);
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
    if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
      LWIP_ASSERT("data included but not checksummed",
        seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
    }

    /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
    acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
             &(pcb->remote_ip),
             IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
    /* add payload checksum */
    if (seg->chksum_swapped) {
      seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
      seg->chksum_swapped = 0;
    }
    acc += (u16_t)~(seg->chksum);
    seg->tcphdr->chksum = FOLD_U32T(acc);
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
    if (chksum_slow != seg->tcphdr->chksum) {
      LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
                  ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
                  seg->tcphdr->chksum, chksum_slow));
      seg->tcphdr->chksum = chksum_slow;
    }
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
  }
#else /* TCP_CHECKSUM_ON_COPY *//*校验和相关*/
  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
         &(pcb->remote_ip),
         IP_PROTO_TCP, seg->p->tot_len);
#endif /* TCP_CHECKSUM_ON_COPY */
#endif /* CHECKSUM_GEN_TCP */
  TCP_STATS_INC(tcp.xmit);

#if LWIP_NETIF_HWADDRHINT
  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
      IP_PROTO_TCP, &(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
      IP_PROTO_TCP);//IP层发送接口
#endif /* LWIP_NETIF_HWADDRHINT*/
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值