• 不可靠不重传的假 TCP


    还是那个面试题:如何用 TCP 实现不可靠传输?… 本文有趣,黑科技,仔细看。

    TCP 是"运营商友好"的。运营商依据 TCP 状态机能以任意粒度对 TCP 连接进行任意管控,包括不限于限速,整形,重置,计费,TCP 和运营商是互惠的。

    UDP 像脱缰野马变幻莫测,运营商只能一刀切,比如高峰期给所有 UDP 流量仅 10 % 的资源份额。

    让运营商看起来是 TCP,但实际上是 UDP,可以考虑做一个假 TCP 封装。

    最简单的,把 IP 协议号从 UDP(17) 改成 TCP(6),复杂点就换个传输头,都可取。比如换头:
    GitHub - marywangran/pseudotcp-tunnel

    此外,各大厂也有各类冠以自研修饰的 XX 协议,它们有多么复杂自然不必多说,主要目的是卷。

    我给一个 10 行代码实现的假 TCP,找到 Linux 内核 tcp_data_queue 函数,从注释处增加代码:

    static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
    {
            struct tcp_sock *tp = tcp_sk(sk);
            bool fragstolen;
            int eaten;
    
            if (sk_is_mptcp(sk))
                    mptcp_incoming_options(sk, skb);
    
            if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
                    __kfree_skb(skb);
                    return;
            }
    
            skb_dst_drop(skb);
            __skb_pull(skb, tcp_hdr(skb)->doff * 4);
    
            // 增加下列 if 语句 13 行代码,暂硬编码 5001 端口,只为 iperf 测试。
            if (inet_sk(sk)->inet_num == 5001 && after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
                    struct sk_buff *nskb;
                    u32 n = TCP_SKB_CB(skb)->seq;
                    if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp)))
                            goto out_of_window;
                    nskb = skb_copy_expand(skb, n - tp->rcv_nxt, 0, GFP_ATOMIC);
                    if (likely(nskb)) {
                            skb_put_padto(nskb, n - tp->rcv_nxt + skb->len);
                            consume_skb(skb);
                            skb = nskb;
                            TCP_SKB_CB(skb)->seq = tp->rcv_nxt;
                    }
            }
    
            tp->rx_opt.dsack = 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    将这代码部署在接收端,事竟成。

    意思是保证发送端 una 不断前推,不会收到 sack 和 dupack,也就不会重传。如下图:
    在这里插入图片描述
    简单说,收到空洞,空洞立即被填充,丢包补零不重传,这种粗暴策略意味着即使真发生乱序,数据也会被 0 填充掉。但简单啊。

    看效果:
    在这里插入图片描述
    解释一下测试结果,为什么假 TCP 对丢包无感。

    假 TCP 是有损传输,iperf 并不校验这种有损,所以即使结果带宽很大,有效的到达数据却随丢包率增加而减小。strace 观测 iperf 接收端实际接收到的数据:
    在这里插入图片描述
    这些 0 即被填充的 0,即有损传输的体现。丢包率越高,0 的比例越高。

    结合优质高尚的编码可最大限度消除有损传输的质量伤害,还记得传皮鞋那个吗?参见:有损传输示例

    再举一例。用有损传输方式接收一个 HTML 文档,会是一堆乱码吗?并不会。

    若有数据丢失,至多丢失一些 HTML 标签和内容,HTML 标签封闭嵌套特点使标签自动补全变得可行且容易,最终依然可得到一个虽缺失部分内容但浏览器依然可展示的文档。

    不仅如此,这些 0 还有妙用。通过分析一段时间内这些 0 的分布,绘制一幅拥塞画像是高尚的。
    说说假 TCP 有什么用,到底哪里需要把 UDP 伪装成 TCP?

    仅在接收端部署那 13 行代码,TCP 就五脏俱全了,这本就是一个真的 TCP,足以糊弄运营商的行为也就不能叫欺骗。除了不重传,TCP 的特性一样不少。

    不重传意味着传输有损,收益是消除了重传时延,非常适合承载时延敏感的业务,如 VNC,流媒体。它适合传输任何 UDP 数据,以绕过运营商对 UDP 的一刀切管控,用这个协议搭建的隧道是通用,高尚的隧道。

    两三事:

    • 常见的面试题,如何用 UDP 实现可靠传输,但不高尚。高尚的面试题应该是,如何用 TCP 实现不可靠传输。
    • TCP 的不可靠传输:TCP的不可靠传输
    • 搭建隧道时还在 TCP 和 UDP 中二选一吗?
    • 还在自研万行代码级的协议吗?本文只是个把戏,实际可以做得更好,比如给个窗口 Buffer,允许乱序的发生,Buffer full 了才补零。
    • 黑科技每周都有,你肯看,我就有。

    周中有朋友问起假 TCP 的事,我说抽空写一篇。这种协议要看你想要多假,可以只封装个 TCP 头,但要更逼真,就要能让运营商设备识别 Session,这一步很重要,运营商正是因为容易识别 TCP Session,才视 TCP 为友好的。于是假 TCP 变得复杂… 反着做,在真 TCP 上做减法,把约束一个个卸掉,直到它足够假,也就假亦真时真亦假了。当然,三次握手要斟酌,对于长连接,这无关紧要,可对于短连接,重试成本低到是否可靠也同样无关紧要。不过我依然有办法连三次握手也优化掉,不过要下回分解。

    浙江温州皮鞋湿,下雨进水不会胖。

  • 相关阅读:
    可信(隐私)计算
    k8s配置集ConfigMap详解
    Java面试题
    Helm Subcharts And Global Values practical operation
    c++ 继承
    Android开发基础——广播实践
    UE5 ChaosVehicles载具 增加方向盘动画 (连载三)
    0021-0022:华为OD机考:消耗资源总数-数组合并
    Js----Math
    VeRA: Vector-based Random Matrix Adaptation
  • 原文地址:https://blog.csdn.net/dog250/article/details/126312744