V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
drymonfidelia
V2EX  ›  程序员

如果只用 Nginx 等现成的 HTTP Server 搭建 HTTP 服务,不自行建立 TCP 连接,是否就不用考虑 TCP 粘包这类传输层的问题?

  •  
  •   drymonfidelia · 10 天前 · 3935 次点击
    68 条回复    2025-04-22 14:56:45 +08:00
    unused
        1
    unused  
       10 天前 via Android   ❤️ 17
    出警!
    MossFox
        2
    MossFox  
       10 天前   ❤️ 1
    还在粘还在粘

    有 http(s) 这种上层协议了就别担心粘了,帮你分好了的,闭着眼放心用。
    seers
        3
    seers  
       10 天前 via Android
    http 已经在应用层了
    laikick
        4
    laikick  
       10 天前
    字节流怎么粘??
    drymonfidelia
        5
    drymonfidelia  
    OP
       10 天前
    @laikick 例如前一个包没发完又发出了下一个包
    dilu
        6
    dilu  
       10 天前
    @unused 出现了,“粘包警察”!!!
    laikick
        7
    laikick  
       10 天前
    @drymonfidelia 那不是你代码写的有问题吗? 建议去看看 recv 和 send 的函数
    momocraft
        8
    momocraft  
       10 天前
    楼主怎么当上 mod 的 介绍下经验
    drymonfidelia
        9
    drymonfidelia  
    OP
       10 天前
    @laikick 具体是什么问题?如果两个包长度过大的话确实有可能出现这种情况吧
    drymonfidelia
        10
    drymonfidelia  
    OP
       10 天前
    如果需要长连接的话是否也可以通过包一层 websocket 来解决 TCP 粘包?
    @seers
    @MossFox
    sigma65535
        11
    sigma65535  
       10 天前
    应用层才有包的概念,tcp 是字节流
    laikick
        12
    laikick  
       10 天前
    @drymonfidelia 做好分包啊. 不过为什么要自己实现一个 tcp 协议呢?
    neoblackcap
        13
    neoblackcap  
       10 天前
    http 协议已经是应用层协议了,nginx 会按照一个个 http 请求转发。nginx 的 http 协议解析属于教科书级别,基本上不用考虑人家会写错。
    如果你需要长连接的,请去学习一下 TCP 编程。否则对 TCP 模型不了解,你还无脑上,那就是刻舟求剑。
    oneisall8955
        14
    oneisall8955  
       10 天前
    通通抓起来
    drymonfidelia
        15
    drymonfidelia  
    OP
       10 天前
    @laikick 我就是不想自己实现,所以才问是不是套个 http/ws 就没有粘包问题了啊
    ragnaroks
        16
    ragnaroks  
       10 天前
    如果是想找个类 tcp 的东西拿来用,又不用考虑从中解析数据,那把 websocket 当 tcp 用是可以的,websocket 会确保每次 onMessage 都是一个完整的包
    henix
        17
    henix  
       10 天前
    nginx? 应该用编程语言的库或框架吧,比如 java 的 netty 或 Python 的 twisted
    推荐用 zeromq 的 request-reply 模式,把底层的 TCP 封装了
    kingcanfish
        18
    kingcanfish  
       10 天前
    @unused 可恶啊 被你抢了一楼
    LoNeZ
        19
    LoNeZ  
       10 天前
    有时间发帖, 不如直接问 AI ... 要不先把整个协议栈理解一遍?
    iseki
        20
    iseki  
       10 天前 via Android
    他们的意思是没有“粘包”这个说法,你说的现象存在,但你不该将之视为一个问题。
    jworg
        21
    jworg  
       10 天前
    分好几种情况,你想问哪一种,HTTP 与 HTTP2 以及 sni proxy 与 static serve 做的似乎都不一样。如果是最简单的 HTTP + static serve 就是 \r\n 换行魔法呗。
    roundgis
        22
    roundgis  
       10 天前 via Android
    http 還粘啥。
    jiangzm
        23
    jiangzm  
       10 天前
    http 服务为什么要考虑 tcp 问题,也不用考虑长链接问题。
    Keuin
        24
    Keuin  
       10 天前
    2025 年了还在粘包
    xuwen
        25
    xuwen  
       10 天前
    按照协议规定读 tcp 数据,压根就不存在粘包的问题。http 服务本来就已经按照协议规定读包了,所以压根就不存在这种东西
    duzhuo
        26
    duzhuo  
       9 天前
    感觉可以复习一下计网分层那里
    HTTP 作为上层协议,无需关心网络传输细节,只需通过 TCP 接口发送/接收数据。
    lqw3030
        27
    lqw3030  
       9 天前
    @drymonfidelia #10 建议把基础原理了解下,会高效不少
    kitrap
        28
    kitrap  
       9 天前 via Android   ❤️ 3
    粘包这傻叉说法是从哪来的?
    kzfile
        29
    kzfile  
       9 天前
    我记得 2018 年论坛里就有粘包警察了
    wangtian2020
        30
    wangtian2020  
       9 天前   ❤️ 1
    粘包从来不是问题,只是现象,一种符合通信协议的现象。
    有些人非要自己不用库,自己去处理连接,那就自己处理这种情况
    zhangsanfeng2012
        31
    zhangsanfeng2012  
       9 天前
    粘包,你们读"zhan bao"还是"niao bao"
    liu731
        32
    liu731  
       9 天前
    买了台发动机担心齿轮坏了是吧?
    rrfeng
        33
    rrfeng  
       9 天前 via Android
    最近被 mtu mss gso tso 折腾
    粘包能不能粘高级点
    mmdsun
        34
    mmdsun  
       9 天前
    还好这是 25 年,不然 OP 要被粘包警察喷死。
    FishBear
        35
    FishBear  
       9 天前
    websocket http https 都是跑在 tcp 上的哦(除了新的 quic 在 udp 上)
    nginx 跑的 http https 也是在 tcp 上的哦

    tcp 性能最高 封装一次就损耗一次性能.

    粘包这个词不大好,应该是我们 csdn 博客创造出来的概念?
    tcp 只关心流,不关心你的数据,你应该自己解数据流.
    zwb9412
        36
    zwb9412  
       9 天前
    好奇 OP 为啥有 MOD 权限?
    darklinden
        37
    darklinden  
       9 天前
    http 和 websocket 是在协议封包的,也就是说如果一个库实现了 http 或者 websocket ,当你使用这个库的时候,面对的接口就只有“包”为单位,不存在“粘”
    cheng6563
        38
    cheng6563  
       9 天前
    不自行建立 TCP 连接,那你是用 UDP 咯,UDP 那就你自己全得考虑了哦。
    sola97
        39
    sola97  
       9 天前
    笑死,我上个月去面试一家小公司,面试题里就有问粘包是什么
    cnuser002
        40
    cnuser002  
       9 天前   ❤️ 2
    楼主的担忧我能理解。比如一个发送端,一个接收端。

    我当然希望每次接收端收到,都是一个完整的消息,不就能直接处理了么?

    但如果这个消息,真的很大呢? 或许他一次发送不完,那我收到的就不全。我要等,这可就麻烦了呀。同样的,下一次把之前的尾巴,跟下个报文的头給一起发送了,我还得拆,更麻烦了。

    嗯。Tcp 它就有这种操作,这不是它的问题,而是它的设计,就是基于 Stream ,像流水一样一直给你灌数据。 底层打散但是保证消息还是前后有序进来的。对于这种流,需要按流的处理方法,收取后进入缓冲区,然后在缓冲区里,根据协议里面的约定,比如固定包头,特殊符号来解析出内容。

    而这个就是 HTTP 干的事情。 所以你的需求,用 HTTP 就可以实现。你可以认为 HTTP 接口每次拿到的,就是完整的数据。

    WebSocket 也可以。
    deplives
        41
    deplives  
       9 天前
    都 5202 年了,还搁这粘包呢? tcp 还在字节流层面,都没有所谓数据包的概念,搁这粘啥呢
    monkeyWie
        42
    monkeyWie  
       9 天前 via Android
    还在粘包,逮捕
    strobber16
        43
    strobber16  
       9 天前
    v2ex 常态化整治粘包斗争成效显著
    mhycy
        44
    mhycy  
       9 天前
    暴论!半桶水 java 书籍害人不浅
    tangchi695
        45
    tangchi695  
       9 天前
    TCP 警察出警!
    macaodoll
        46
    macaodoll  
       9 天前
    抓起来抓起来
    julyclyde
        47
    julyclyde  
       9 天前   ❤️ 1
    你只要别
    亲自在 socket 上执行 read 、write 、recv 、send
    基本上都没事

    你只要 *面向 request 编程* 而不是 *面向 stream 编程* 就可以把 *从 stream 里截出 request* 这个工作外包给 library

    需要强调的是:
    正常人无法对 TCP 的 segment 进行处理,正常人只能看到 TCP 是一个 stream
    hayala
        48
    hayala  
       9 天前
    这个帖子看着很欢乐
    Mystery0
        49
    Mystery0  
       9 天前 via Android
    @zhangsanfeng2012 读 nian bao
    catamaran
        50
    catamaran  
       9 天前   ❤️ 2
    @Mystery0 虽然我也念 nian bao ,但是应该是 zhan 包,包 zhan 在了一起,动词,指的是一种现象。nian 一般用作形容词,比如粘豆包。再比如:这个胶很 nian ,所以 zhan 的很结实。
    maigebaoer
        51
    maigebaoer  
       9 天前 via Android
    抓起来!
    yolee599
        52
    yolee599  
       9 天前 via Android
    说 TCP 粘包属于常识性错误,因为 TCP 协议就像一条水管,会源源不断的给你数据,它只负责把数据按先来后到的顺序交给你。
    至于你需要一包一包的应用数据,那是应用层该干的事情,应用层需要给 TCP 数据一个边界标识,再通过这个边界标识来解析数据,如果还没检测到边界就暂存到自己开辟的缓冲区中,等检测到了边界就返回缓冲区里的数据,就够成了一个应用包。
    xuanbg
        53
    xuanbg  
       9 天前
    应用层协议譬如 http 不就是用来给你封一个个包的嘛,既然封装好了包,就不会稀里糊涂粘在一起了,你大可以放心使用。至于 TCP 协议么,那是个数据流,并没有包的概念,所以也不存在粘不粘的。

    再往下 IP 协议倒是分包的,就像一个个邮包,上面贴着收件人地址,路由器就是靠这个地址来转发数据包的。但路由器只管转发,并不管你包里面装的什么东西。
    echoechoin
        54
    echoechoin  
       9 天前
    @drymonfidelia #9 每个报文都需要一个头部,头部存放长度就行
    me1onsoda
        55
    me1onsoda  
       9 天前
    @laikick #4 不就是字节流才会沾吗?
    iceheart
        56
    iceheart  
       9 天前 via Android   ❤️ 3
    整天粘包,吸管喝饮料,难道吸上来的是一块一块的?
    ipwx
        57
    ipwx  
       9 天前
    楼主的需求是啥?

    如果用 websocket 发送一个 message ,那它天然就是按 message 切分的,没问题。但是,message 有大小上限。如果你需要发送一个超过上限的 message ,你可能需要自己模拟一遍 “拆包”-“组装” 过程,相当于你用 websocket 消息流模拟了 tcp 的无消息流。

    如果你想要在读取 post body 的时候期待客户端是一个一个数据包发送的,那不好意思,中间任何一个代理服务器甚至是路由器都可以修改数据包的形式,是可以任意重新组装重新切分的。
    xiaomushen
        58
    xiaomushen  
       9 天前
    受不了,这都粘了 30 多年了吧?
    liuguang
        59
    liuguang  
       9 天前
    根本不存在粘包,粘包都是源于读取方法。
    masterclock
        60
    masterclock  
       9 天前
    2025 年了,还能出现 tcp 粘包 这词,我是没想到的
    franswish
        61
    franswish  
       9 天前
    很久很久以前还是学生的时候,搞嵌入式设备测试,用串口做上下位机通信,每帧报文几十字节不等,数据周期性发送,间隔固定且可调(从几百毫秒到数秒),简单做一个定时接收逻辑即可满足需求,不需要再做应用层根据帧头帧尾校验分帧。
    后来用以太网口,走 TCP 协议做差不多的事,但是数据量大了很多,通信也变成非周期性且短间隔的了。还按原来串口的思维去理解 TCP ,发现完全搞不定,然后才领悟了为什么数据要有帧头帧尾校验,TCP 只负责收发数据的可靠性和连续性,要用数据得应用层自己去解。
    结合我自己经历,我觉得喜欢说“粘包”的怕不是像我以前认知串口的一样,发一次就是一帧所以通过调整接收逻辑能一次收到完整一帧就不用在接收端先分帧再解帧了。
    kneo
        62
    kneo  
       9 天前 via Android
    正经回答下,不用。
    ipwx
        63
    ipwx  
       8 天前
    @franswish 不知道怎么搞定协议解析、切分消息(俗称解决粘包) = 我高中玩编程的水平。

    那时候是真觉得这玩意儿也忒复杂了,怎么这么难搞。

    现在嘛,不就是把 TcpConn 放到一个 Stream 里面,然后

    string readNextChunk(int size) {
    int nLeft = size;
    string ret;
    char buffer[8192];
    while (nLeft > 0) {
    int nRead = read(conn, buffer, min(nLeft, sizeof(buffer));
    if (nRead == 0) {
    break; // EOF
    }
    for (int i=0; i<nRead; ++i) {
    ret.push_back(buffer[i]);
    }
    nLeft -= nRead;
    }
    return ret;
    }

    其实第一个认知更新,是在网络条件下,read(..., 8192) 不一定能给你真的读出来 8192 bytes ,你得用循环读。然后这部分写成一个通用函数(比如上面这个 readNextChunk) 就行了。用的时候

    int nextMsgLength = fromLittleEndianUint32Bytes(readNextChunk(4));
    string msg = readNextChunk(nextMsgLength)
    zxjxzj9
        64
    zxjxzj9  
       8 天前
    http 都已经包了一层应用层了你怎么粘。只有自己读 tcp 字节流,把字节流拆成了一小段之后读,读不干净才会粘啊!
    codingmiao
        65
    codingmiao  
       8 天前
    粘包警察是什么梗,自己 netty 写个通信,还是要考虑粘包半包的嘛
    csfreshman
        66
    csfreshman  
       8 天前
    在 v2 ,关键字"粘包"自带流量………
    julyclyde
        67
    julyclyde  
       8 天前
    @yolee599 tcp 并非源源不断,而是经常断。指定长度读,结果没收到那么长的数据,但是等会再读发现又有了
    所以才会产生这些问题
    qbmiller
        68
    qbmiller  
       2 天前
    感谢 dubbo ,让我学习了一次粘包。2.6.x 版本的 thrift 协议。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1398 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 16:59 · PVG 00:59 · LAX 09:59 · JFK 12:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.