linuxTCP数据包重传过程—-小结下载
于TCP/IP协议栈的TCP协议的重传功能是由在linux内核源码(net/ipv4/tcp_output.c)中的函数tcp_retransmit_skb()实现的代码如下: /* 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;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.*///说明在发送缓存区中消耗了许多内存去做其他的工作(比如分片等,只有1/4的缓存才是保留给这些工作的),暂时不能重传if (atomic_read(&sk->sk_wmem_alloc) > min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf))return -EAGAIN;//检测重传的段,接收方是否已经收到其部分或者全部,如果知识兔收到则说明有bug ,否者就调整TCP段的负荷,即删除SKB缓存区//前面部分已经接收到的数据if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))BUG();if (tcp_trim_head(sk, skb, tp->snd_una – TCP_SKB_CB(skb)->seq))return -ENOMEM;}//根据目的地址等条件获取路由,如果知识兔获取路由失败就不能发送if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))return -EHOSTUNREACH; /* Routing failure or similar. */ cur_mss = tcp_current_mss(sk); /* 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.*///如果知识兔接收方已经减小了窗口,并且知识兔带重传的SKB已经不在新的窗口内,则不能重传该SKB,//有一种情况例外,就是接收方的接受窗口减少为0,在这种情况下会发送0窗口探测段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. */} else {int oldpcount = tcp_skb_pcount(skb); if (unlikely(oldpcount > 1)) {tcp_init_tso_segs(sk, skb, cur_mss);tcp_adjust_pcount(sk, skb, oldpcount – tcp_skb_pcount(skb));}} tcp_retrans_try_collapse(sk, skb, cur_mss); /* 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 & TCPHDR_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);//发送SKB if (err == 0) {/* Update global TCP statistics. */TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS); tp->total_retrans++; #if FASTRETRANS_DEBUG > 0if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {if (net_ratelimit())printk(KERN_DEBUG “retrans_out leaked.”);}#endifif (!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 += tcp_skb_pcount(skb); /* 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;}我们知道,TCP的发送是有一个SKB 队列如图,这样维持一个发送队列,如果知识兔收到发送了SKB的ACK,就将对应的SKB从队列中删除掉,在函数tcp_retransmit_skb中我们可以看到,接受方游有可能只是收到了部分SKB的数据,那么就将收到的SKB的数据删除掉,这样可以节省缓存空间这里注意的到函数tcp_retransmit_skb()最终的是调用函数tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);将SKB发送出去,而构造TCP的头部信息在函数tcp_transmit_skb()中,下面是函数tcp_transmit_skb()构造TCP头部的片段 所以也就是说在发送队列中的SKB是没有头部的,这也是方便了选择重传等功能/* Build TCP header and checksum it. */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);
本文来自系统大全为您分享如需转载请注明!推荐win10下载
下载仅供下载体验和测试学习,不得商用和正当使用。