V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DonaldY
V2EX  ›  程序员

分享文章: TCP 粘包? TCP 警察什么梗

  •  
  •   DonaldY · 278 天前 · 10126 次点击
    这是一个创建于 278 天前的主题,其中的信息可能已经有所发展或是发生改变。

    文章地址:TCP 粘包? TCP 警察什么梗

    从 v2 学到很多,按照自己理解总结了下。0.0

    89 条回复    2022-08-31 19:22:43 +08:00
    zjp
        1
    zjp  
       278 天前 via Android
    讲拆包粘包的很大比例是 Javer ,Netty 权威指南功不可没…
    jiulang
        2
    jiulang  
       278 天前   ❤️ 8
    TCP 粘包?伪命题,tcp 从来不是像 UDP 一样,以包设计的,而是流式的,就像滔滔不绝的流水一样。
    RRyo
        3
    RRyo  
       278 天前   ❤️ 15
    有请双方选手入...哦 2L 已经入场一位!
    winterbells
        4
    winterbells  
       278 天前   ❤️ 1
    好久没有这个话题了,恭喜 lz 找到了热点
    wanguorui123
        5
    wanguorui123  
       278 天前
    警察看了头疼
    mywaiting
        6
    mywaiting  
       278 天前   ❤️ 1
    粘包一词到底是怎么造出来的,我很是好奇

    PS 每每看到粘包警察一词就想笑
    TWorldIsNButThis
        7
    TWorldIsNButThis  
       278 天前 via iPhone   ❤️ 15
    粘念 zhān 还是 nián ?
    xlsepiphone
        8
    xlsepiphone  
       278 天前
    原封不动的把一篇文章看完了,耗时 10 分钟。
    mringg
        9
    mringg  
       278 天前
    警察已经开始摆烂了
    qrobot
        10
    qrobot  
       278 天前   ❤️ 8
    TCP 粘包是啥? 自己创造一个名词出来? TCP 从来没有粘包一说, 看你的文章你也是对 TCP 一知半解。 麻烦赶紧删了,免得误人子弟。

    我先跟你说,很明确的来说 TCP 没有粘包这一个说法,根本就不存在。


    我看你用 Java 写的代码, 那么我就用 Java 代码给你举个例子

    ```
    Socket socket = new Socket("127.0.0.1", 8000);
    OutputStream os = socket.getOutputStream();
    os.write("test".getBytes());
    ```

    实际上会发生什么?

    如果网络延迟,或则发生丢包,那么会超时重传. 然后网络线路没问题, 那么会直接写入系统的 TCP/IP buffer 里面去。

    如下


    ```
    Socket socket = new Socket("127.0.0.1", 8000);
    OutputStream os = socket.getOutputStream();
    os.write("test".getBytes());
    os.write("test1".getBytes());
    os.write("test3".getBytes());
    ```

    那么我写入三次表示什么? 很显然根据我上面说的,系统为了性能会缓存对应的 TCP/IP 的数据信息, 那么我可以采用一个很大 buffer 来进行一次性将这两次的请求给直接读取过来。


    根据这个理解那么就可以把 TCP 看作流, 通过流来进行运输货物,很显然明显的是 TCP 就是流协议。 流协议何谈封包和拆包?


    那如何解决判断 TCP 中这次请求的信息已经是末端了?

    很常见的两种方案


    1. 一次请求一次响应, 后续关掉 socks
    2. 用 4 字节定义一个无符号的整数来定义这个报文的 Length 就好了


    所谓的 `特殊分隔符`简直是最愚蠢的做法, 难道我的报文中就不能出现对应的特殊符号吗? `固定消息长度` 简直是浪费内存和网络开销。完全不可取。


    因为是流协议, 所以需要应用自己去判断写入的字节什么时候已经达到的末端。
    tairan2006
        11
    tairan2006  
       278 天前
    其实这块儿的中文术语很模糊,报文、帧、数据包啥的,用英文表达会好一点。

    有的书把 packet 翻译成报文,有的把 message 翻译成报文,服了…
    yyf1234
        12
    yyf1234  
       278 天前 via iPhone   ❤️ 1
    eason1874
        13
    eason1874  
       278 天前   ❤️ 3
    热帖预订。顺便提示楼主,还有一个流量密码:HTTP 状态码一律 200 、HTTP 请求方式一律 GET/POST
    TomVista
        14
    TomVista  
       278 天前
    无所谓了,只要你能听明白, 需要一个上层协议来拆分信息就行

    前一阵子有个沙雕,非要我发送的时候,给他拆好 .dog

    我接收的怎么是这样子 .jpg
    你那里有问题 .jpg
    不是我的问题 .jpg
    不是我负责的 .jpg
    你前端改改 .jpg
    darkengine
        15
    darkengine  
       278 天前   ❤️ 1
    TCP: 我把东西按顺序给到你了,我们也不知道你们发的啥玩意儿,自己看吧
    qrobot
        16
    qrobot  
       278 天前
    当我看到 TCP 粘包的时候,我很震惊, 后面我开始解释 TCP 没有粘包, 只有 “因为是流协议, 所以需要应用自己去判断写入的字节什么时候已经达到的末端。” 后来我渐渐的麻木......
    mercury233
        17
    mercury233  
       278 天前
    TCP 粘包就是理论上不存在但实际上必须处理的东西 /狗头
    Rache1
        18
    Rache1  
       278 天前   ❤️ 2
    这页面上乱七八糟的元素,我还以为我打开了内容农场

    stoluoyu
        19
    stoluoyu  
       278 天前
    @zjp 死去的回忆开始攻击我
    miyuki
        20
    miyuki  
       278 天前 via iPhone
    packet frame message
    跨频道聊天是吧
    nothingistrue
        21
    nothingistrue  
       278 天前
    四层传输层 TCP 协议流式,七层应用层通过缓冲区映射成数据包处理,说粘包并没错。但是“粘包”这个词是生造的,用于新手快速理解还可以,再深入点就该换成“分帧取帧”,或者“帧解码”。
    qrobot
        22
    qrobot  
       278 天前
    @nothingistrue #21 你确定你理解的是楼主所说的问题, TCP 帧在应用层是不关心的。 而所谓的 “判断写入的字节什么时候已经达到的末端” 是需要自己解析的

    而且你说的 “分帧取帧”,或者“帧解码”。 是指什么? 说的是 解析 RFC 793 里面的 `TCP Header Format` 吗? 很抱歉,在用户使用协议上,没有权限读取对应的 `TCP Header Format` , 要么使用 tun/tap 等虚拟网卡, 要么使用 pcap/winpcap/npcap 或则 win10 的驱动网络拦截。 但是这些 TCP 协议的操作,往往都不是 TCP 使用用户来进行操作的, 楼主很明显是在使用 TCP 协议, 而不是解析 TCP 协议
    easonzh
        23
    easonzh  
       278 天前
    @Rache1 什么叫字节文化啊(后仰
    tool2d
        24
    tool2d  
       278 天前
    HTTP1.0 好像就是根据 connection:close ,来判断 HTML 是否已经完全传输完毕。

    也不是所有的 TCP 都有 content-length 属性,在那个 IE 时代,经常遇见下载到一半的网页突然断开。
    someonedeng
        25
    someonedeng  
       278 天前
    在 TCP 这层不用考虑这个
    lysS
        26
    lysS  
       278 天前
    TCP 有所谓的“粘包”是使用情景出错了,你把两个以上的数据报放在一个 tcp 流里面传输了;正常的应该是一个“包”一个连接。像 HTTP 的长连接就是这种情况,不过 HTTP header 有 length 可以解决“粘包”
    nothingistrue
        27
    nothingistrue  
       278 天前
    @qrobot #22 网络通信是七层,不要死扣在传输层 TCP 协议这一个上。帧的英文是 Frame 。还有不要再回复了,这贴是给楼主的内容农场引流的,正方反方意见都不重要,都会给楼主引流。
    reallynyn
        28
    reallynyn  
       278 天前
    他们说的 tcp 粘包,应该是指 nagle 算法吧。。
    oneisall8955
        29
    oneisall8955  
       278 天前 via Android
    exiledkingcc
        30
    exiledkingcc  
       278 天前
    TCP 没有包,但是这篇文章非要把指出这个事实的人扣一个“粘包警察”的帽子,似乎还有点得意。
    基于错误的概念讨论一大堆东西都是没有意义的。
    就这篇文章来说,TCP 的包是啥它自己清楚吗?
    是你调用一次 socket write 的数据,还是 wireshark 抓包看到的一个 TCP 的条目?还是你应用层自己定义的逻辑结构?
    概念都不定义清楚就自说自话,就是一堆废话。
    TsubasaHanekaw
        31
    TsubasaHanekaw  
       278 天前
    掘金在某些人看来已经是内容农场了么 哈哈哈
    国内要啥社区生态啊
    boywang004
        32
    boywang004  
       278 天前
    就喜欢看这种话题,掐!打起来!别停手!
    小马扎、花生米已经就位啦!
    qwerthhusn
        33
    qwerthhusn  
       278 天前   ❤️ 1
    奥山 YY 来人
    hankai17
        34
    hankai17  
       278 天前
    之前也看过很火的几个黏包警察的帖子
    面试的时候也被问过 大概就是解决黏包的方案 比如 <content-length>[content]
    keepeye
        35
    keepeye  
       278 天前
    其实说的不是报文粘包,而是消息解析的问题
    tangchi695
        36
    tangchi695  
       278 天前
    我不管,我的 TCP 就是要粘包[手动狗头]
    fkdtz
        37
    fkdtz  
       278 天前
    TCP 只保证可靠数据传输,没说把数据一个个拆开好给你,这件事应该由上层协议负责处理。
    如果是这样的话,你也可以提出这样一系列问题:
    如何解决 IP 协议不能可靠数据传输的问题?常规解决方案是用 TCP ;
    如何解决 Ethernet 协议与全球服务节点连接问题?常规解决方案是使用 IP 协议;
    ...
    回过头来看,这正是「分层」思想的奥义所在啊,每一层只处理好自己的事儿。
    MrLin
        38
    MrLin  
       278 天前
    ·粘包·真是误人子弟,还有一大堆捧的,还在那里抠概念,错的就是错的
    djoiwhud
        39
    djoiwhud  
       278 天前 via Android
    @reallynyn

    和 nagle 没任何关系。无论怎样,接收端读都可能会读取不定次数写的内容。

    我无法理解这里在嘲讽 tcp 粘包的什么问题。这确实是工程中需要处理的内容。
    byte10
        40
    byte10  
       278 天前
    @fkdtz 这解释到位,可以。

    好几年前我一直认为 tcp 粘包是一个非常复杂的事情,一直没认真去看,后来要面试就专门去看 TCP 粘包。tmad 差点颠覆我的认知,这算个屁粘包,不知道哪个土鸡 提出来的。后来终于看到 V2 原来也有很多人不认可这个事情,那我就放心了,原来我的认知没错,某些人的问题。。。
    0o0o0o0
        41
    0o0o0o0  
       278 天前   ❤️ 1
    生造词只会把问题弄得更复杂,明明很简单的原理,一句话就能说清楚的事情,非要生造一个词,然后再写一篇文章来解释这个词,把问题弄得更复杂。
    还有,你说人家是“tcp 警察”,我觉得你是“tcp 恐怖分子”
    nekoneko
        42
    nekoneko  
       278 天前
    @zjp #1 javer 表示不背这个锅
    nekoneko
        43
    nekoneko  
       278 天前
    tcp 流式传输哪来的包, 脑袋里长了个包吗...
    cweijan
        44
    cweijan  
       278 天前
    @mercury233 这种情况也不能叫 tcp 粘包, 叫应用层粘包才对.
    DonkeyBenjamin
        45
    DonkeyBenjamin  
       278 天前
    这就是中文 cs 界的恶心之处,总是发明一些莫名奇怪的称呼。英文 tcp framing tcp stream 就很直观
    bug123
        46
    bug123  
       278 天前
    十年前看网络编程书籍的时候有“tcp 粘包”的说法,其实是说需要一个业务协议去分包,比如:length + body 的格式,懂得都懂,每天没事做就拿出来喷一次,何必呢
    zachgenius
        47
    zachgenius  
       278 天前
    粘包 难道不是“碰瓷”的意思? emmmm, 这个标题我都没看懂......TCP 警察......你再说某夫网?
    icyalala
        48
    icyalala  
       278 天前
    早上看到帖子乐了,以为大家会调侃一下粘包警察的耿
    结果。。哈哈哈
    moremoney
        49
    moremoney  
       278 天前   ❤️ 11
    看到“TCP 粘包”这个专有名词,我表示极度震惊。连夜打车回到家里,战战兢兢翻开《计算机网络》,拿着放大镜仔细看了半夜,也没看到“粘包”两个字。我的后背不觉地渗出致密的汗水,双手止不住地发抖。匆忙打开电脑,一篇篇地翻着论文,试图寻找关于这个词的信息。可眼看天就要亮了,我依旧一无所获。我失望的躺在床上,满脑子都是“粘包,粘包,粘包!”,横竖睡不着,不得已打开了知乎,写下了一个问题“究竟什么是 TCP 粘包”。不一会儿答案就如雪花儿般涌了出来,每一片雪花上都写着一句话“TCP 没有粘包”。我颤抖的双手终于停了下来,一股热流从我心底涌到泪腺。啊,原来我并不孤独。
    agagega
        50
    agagega  
       278 天前 via iPhone   ❤️ 1
    讨论一个东西的前提是得有定义,谁来定义这个 TCP 的包概念?其次,同样是流式读写,没有人会在读写文件的时候说有粘包问题吧?
    DamonLe
        51
    DamonLe  
       278 天前
    哈哈哈哈,每年都有几次粘豆包。[头秃]
    julyclyde
        52
    julyclyde  
       278 天前
    建议粘豆包用户都改用 websocket
    NullData
        53
    NullData  
       278 天前
    @TsubasaHanekaw 掘金已经和内容农村差不多烂了
    xilou31
        54
    xilou31  
       278 天前
    某种意义来说,楼主已经成功了,确实吵起来了 (doge
    leexy
        55
    leexy  
       278 天前
    @TWorldIsNButThis #7 nian 是形容词,大 nian 鼻涕;
    zhan 鼻涕 zhan 手上甩不下来; zhan 胶带。
    所以应该是 zhan 包,
    nian 豆包
    ipwx
        56
    ipwx  
       278 天前
    TCP 确实有“粘包”问题。

    所以为什么要死磕 TCP ?找个 TCP 上层的、有“消息”概念的协议不好嘛?比如 WebSocket ?

    我有些反感粘包警察,是因为早就被标准化解决了无数遍,直接拿来就能用(比如 WebSocket 这个五层协议)的问题,非要当做现实中一个重大问题去翻来覆去地讨论。
    nekoneko
        57
    nekoneko  
       278 天前   ❤️ 1
    分包组包这是网络层干的事情, 跟传输层有什么关系.
    看 ip 协议有个分包组包, 然后造个 tcp 的拆包黏包, 真的是恶心啊, 很容易把基础不行的人带歪.
    nekoneko
        58
    nekoneko  
       278 天前
    @ipwx #56 tcp 都没有包这个概念, 怎么会 粘和拆 呢
    fuge
        59
    fuge  
       278 天前
    nnmlgbb
    ChoateYao
        60
    ChoateYao  
       278 天前
    @ipwx WebSocket 属于第五层?那么为什么握手要基于 HTTP 。
    fan123199
        61
    fan123199  
       278 天前
    搜了下,OP 文章提的都是网络上很多年就有的名词和争议, 怎么都在骂楼主扣帽子。。
    Rache1
        62
    Rache1  
       278 天前
    @TsubasaHanekaw 不是看起来是,而是他已经在朝这方面做,用 Google 搜一下 site:juejin.cn inurl:/s/ 你就能体验到了
    ipwx
        63
    ipwx  
       278 天前
    @ChoateYao 嗯我确实说错了,在通用模型里面属于第四层应用层。HTTP 和 WebSocket 都属于应用层。

    另外如果看 HTTP 和 WebSocket 的关系,实际上 WebSocket 可以独立于传统的 HTTP 服务器单独使用,只不过 Handshake 这一步好像用了 HTTP header 。但如果一整个端口都用于 WebSocket 应用程序的话,其实可以忽略 HTTP 协议这玩意儿。

    WebSocket 单独使用,你可以参考币的交易所协议。
    ipwx
        64
    ipwx  
       278 天前
    @nekoneko 吗吗,你的言论有些“反粘包警察”哦。

    所以其实我“粘包”打引号了。虽然 TCP 确实不存在粘包这个概念,但是在应用中这个“问题”确实存在。我是不关心这玩意儿到底用“粘包”这个术语,还是准确地“因为 TCP 是流式协议所以必须自己处理数据包分割的问题”这么长的文本描述。在我看来,入乡随俗,如果“粘包”接受度广,用“粘包”来代指上面这句话我没意见。
    julyclyde
        65
    julyclyde  
       278 天前
    @tool2d http 1.0 是靠 tcp connection close 来识别的; 1.1 才有 content-length 和 transfer-encoding chunked 这两个功能
    llwwbb7
        66
    llwwbb7  
       278 天前
    @TWorldIsNButThis 谷歌翻译给这个字的音标是 /Zhān/,点发音念的是 nian ,笑死了
    nekoneko
        67
    nekoneko  
       278 天前
    @ipwx #64 所以如果叫 基于 tcp 传输的应用层消息拆分 我是没意见的, 非要叫个 tcp 拆包, 纯属误人子弟
    ynyounuo
        68
    ynyounuo  
       278 天前
    @Rache1 诶?难道不是吗?
    UIXX
        69
    UIXX  
       278 天前
    “你们不要再打了啦”
    qrobot
        70
    qrobot  
       278 天前   ❤️ 1
    @ipwx #64

    我告诉你粘包是怎么来的


    ```
    Socket socket = new Socket("127.0.0.1", 8000);
    OutputStream os = socket.getOutputStream();
    os.write("test".getBytes());
    os.write("test1".getBytes());
    os.write("test3".getBytes());
    ```

    写了三次数据, 然后在调用 read 读取的时候发现写入的数据被一次性读取到了, 所以他 /她认为数据包被粘连在一起了。

    “粘包” 无论是否打引号说出这个词就是对 TCP 协议的不理解,想当然的一个词语。 这种本身就应该抵制。"需要自己判断写入的字节什么时候已经达到的末端", 这就很好的解释了这个问题。


    @ipwx 我没猜错你对 TCP 协议估计也是一知半解 。你写一次 tun 设备的 三次握手和四次挥手, 你就知道所谓的封包 /拆包 /重传 等等, 都已经做好, 数据已经有序的给你了。 你只要操作 Stream 就可以了。


    我在跟你明确一下, 他说的粘包,指的是 代码中 write 两次, 另一端 read 一次的时候就可以读出来。



    @ipwx 或则我这么问你, 如果你发现 TCP 有所谓的粘包, 请截图用 wireshark 抓包并且保存截图让我看看, 你能截屏出来, 我给你奖励 1w
    guang19
        71
    guang19  
       278 天前
    把协议设计好基本不会出现所谓的“粘包”
    msg7086
        72
    msg7086  
       278 天前
    @ipwx #敏感词 有没有可能,你说的这个东西接受度最广的叫法是「协议」。
    Admrial
        73
    Admrial  
       278 天前
    @moremoney 查重率百分之百
    skies457
        74
    skies457  
       278 天前 via iPhone
    @qrobot
    > 所谓的 `特殊分隔符`简直是最愚蠢的做法
    http header 就是靠\n\n....
    lizytalk
        75
    lizytalk  
       278 天前
    所谓“粘包问题”不就是设计一个应用层协议的问题么?在 TCP 协议(传输层)的范畴中,问题不存在就不是不存在...
    ipwx
        76
    ipwx  
       278 天前   ❤️ 1
    @qrobot 我不否认粘包实际不存在。我知道 TCP/IP 。但我觉得既然这么多人叫,那在别人都这么叫的语境下,借用这个术语表达他们的意思,我没意见。。。

    为啥要这么纠结术语的纯洁性。DL 论文里面一堆(数学)术语乱用,只要该 domain 认同,不也就这么过来了。
    sky857412
        77
    sky857412  
       278 天前
    不知道在吵吵啥,听得懂就行,非 BB 半天你这概念不对,描述不对
    adoal
        78
    adoal  
       278 天前
    julyclyde
        79
    julyclyde  
       277 天前
    @skies457 http 是靠\r\n\r\n 吧。不是\n\n 吧?
    e7
        80
    e7  
       277 天前
    别纠结“粘包”这个词翻译对不对,令我震惊的是大多数人好像都不知道这回事
    fatyoung
        81
    fatyoung  
       277 天前
    @qrobot 不用'特殊分隔符'的话,还有其他好法子吗?
    tabris17
        82
    tabris17  
       277 天前
    TCP 粘包,UDP 汤包,ICMP 叉烧包
    vishun
        83
    vishun  
       277 天前
    那 tcp 没有粘包,upd 也没有粘包,粘包这个词是怎么来的?😵
    qrobot
        84
    qrobot  
       276 天前
    @skies457 #74L
    我从未听过 http 协议中用 \n\n 来最为判断文本已经达到的末端。 根据 http 协议 `content-length` 用来判断数据大小是多少, 即使在早期也是 一次请求,一次响应, 用 tcp connection close 来识别的。 请问你说 的 \n\n 是哪个版本?
    0o0o0o0
        85
    0o0o0o0  
       276 天前
    @vishun #83
    说白了就是没有了解 tcp 的原理,没有了解流的概念,导致了 “发送两次,却一次就能全接收了”。
    也就是 “我明明辛辛苦苦把数据分成两次(“他认为这是两个包”)发送,怎么一次就全接收了,肯定是 tcp 协议把我的两个 ‘包’ 粘在一起了” ,所以有了 “tcp 粘包” 这个概念。但是对于 tcp 来说是没有包的这个概念的,是发明 “粘包” 的这个人没有了解 tcp 原理导致的。
    同理,如果一个人只知道流,没有包的概念,那他遇见 udp 就会产生“udp 拆包”,tcp 是保证顺序的,udp 不保证,他还会产生“udp 乱流”的概念,因为不知道一个东西怎么用就强行用会导致无数个“xx 问题”的概念,但是这些概念本身没有什么意义,因为如果一开始就了解一下什么是流,“粘包”这个概念根本就不会产生。
    skies457
        86
    skies457  
       276 天前
    @qrobot 楼上有人纠正过了,是\r\n\r\n.... 这个分隔符用来分割 http header 的 content 的
    Joker123456789
        87
    Joker123456789  
       276 天前
    一个个都在 纠正 TCP 没有粘包, 我看了就头疼,为什么你们接受不了这个形容词呢? 如果你们要纠正,那就请你拿出正确的形容词出来(必须是业内认可,通用的,不能是自己造的)。

    无论你们认不认,有一个事实 已经是既定的了, 那就是听到 TCP 粘包,大家就知道 是接收端 读到了数据,但是数据里 不止一条消息,需要自己去拆分出来。 粘包这个形容词 已经是业内通用了的, 你们非要来纠正,但是又拿不出真正通用的 形容词。

    恕我直言,这种行为叫抬杠。
    julyclyde
        88
    julyclyde  
       276 天前
    @Joker123456789 正确的叫法是“一种对协议进行错误解析的方式”
    xsen
        89
    xsen  
       276 天前
    这个一开始是从 binary protocol 那边过来的,不过那边不叫粘包
    叫 message parser 或者 message pack

    简单来说就叫组包、拆包,这本身就是属于 protocol 层面的问题
    N 年前某一天,突然听到粘包这个词——找了老半天还是没反应过来
    关于   ·   帮助文档   ·   博客   ·   nftychat   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   765 人在线   最高记录 5634   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 61ms · UTC 22:05 · PVG 06:05 · LAX 15:05 · JFK 18:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.