如果客户端和服务端是同步串行的 socket 通信,是不是不用考虑粘包的问题了 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zxCoder
V2EX    问与答

如果客户端和服务端是同步串行的 socket 通信,是不是不用考虑粘包的问题了

  zxCoder 2020-12-11 17:47:12 +08:00 1149 次点击
这是一个创建于 1847 天前的主题,其中的信息可能已经有所发展或是发生改变。

如果客户端和服务端是同步串行的 socket 通信,是不是不用考虑粘包的问题了

就客户端发一个命令,服务端接收处理后发送回复,客户端收到回复,再发送下一个命令

CEBBCAT
    1
CEBBCAT  
   2020-12-11 18:15:54 +08:00   1
等一个
secondwtq
    2
secondwtq  
   2020-12-11 18:43:34 +08:00 via iPhone   1
不如楼主直接”粘包 site:v2ex.com”?
3dwelcome
    3
3dwelcome  
   2020-12-11 18:45:32 +08:00
参考 websocket 协议,必须有包长度。
tcp/ip 强制把流切成一个个小包,是物理层需要。而你 IP 包的发送,必然会存在发送失败,导致过一会儿客户端重发的情况存在。
网络没有 100%的可靠性。所以你程序要健壮,就别假收到的 TCP 包是完整的,能直接处理,多做协议设计才是正途。
Foxkeh
    4
Foxkeh  
   2020-12-11 18:57:24 +08:00
是的, 我们公司有类似场景, 就是这么干的, 注意留校验位.
whileFalse
    5
whileFalse  
   2020-12-11 20:08:17 +08:00
网卡发送信息类似于用菜鸟裹裹呼叫快递员。你想发消息就呼叫快递员,快递员要过一会才能过来。快递员那里有包装箱,一个包装箱能放得下 1500 字节左右的数据。

对于 TCP 连接,你想发一个消息的时候呼叫快递员。快递员还没到,你可能又想发第二个消息了。等快递员来了,你都准备好 3 个消息了。快递员发觉你这三个消息是通过同一个 TCP 连接发出去的,因此把他们打包在同一个快递箱子里了(这三个加起来还没到 1500 字节)用一个快递单号发出去了。这就是粘包。
然后你想发第四个消息,于是再次呼叫快递员。这第四个消息有 1600 字节。快递员发现一个包装箱放不下,于是把你的货拆成了两箱发出去,第一箱 1500,第二箱 100 。第二箱还没装满,如果你有其他消息要发,可以和第二箱一起打包发走。
TCP 是面向连接的,快递员只要发现是同一个连接的数据,就会自动帮你合箱。所以如果你连着发送两坨数据,就有可能粘包。

UDP 则不同。UDP 没有连接,信息与信息之间毫无关系。所以你即使连续发送 100 个每个只有 1 字节的信息,也会分成 100 个快递箱发出去。这绝不会粘包,但坏处是你得付 100 单快递费,性价比低,而且丢了不管。UDP 虽然不能合箱,但提供拆箱服务,如果你想发 1600 字节的数据,UDP 也能帮你拆成两箱。有趣的是,这是一个可选的服务,你可以明确选择声明拒绝拆箱,那么快递小哥发现超重之后会直接拒发快递。(你不用自己检测是否超过 1500 字节,因为有的快递能发大包,一个包能装下 9000 字节)
whileFalse
    6
whileFalse  
   2020-12-11 20:10:57 +08:00
回复 LZ 的问题。如果你一次只发一个包,过很久才发第二个,那肯定不会粘包。但你要注意自己的包大小,如果超过 1500,那会遇到拆箱问题。万一网络一卡 你先收到第一个箱,第二个箱还没到你就去处理数据了,那也会有问题。
misaka19000
    7
misaka19000  
   2020-12-11 20:11:20 +08:00
你怎么知道客户端发的是不是一个命令
zxCoder
    8
zxCoder  
OP
   2020-12-11 21:11:27 +08:00
@misaka19000 假设的情况啊 客户端发一个命令之后要等待回复才能输入第二个命令,这种场景很常见吧
misaka19000
    9
misaka19000  
   2020-12-11 22:15:41 +08:00
@zxCoder #8 socket 是流,你没法判断一个命令是开始还是结束了
zxCoder
    10
zxCoder  
OP
   2020-12-11 22:24:24 +08:00
@misaka19000 可是我一次只发一个命令 也不行吗
misaka19000
    11
misaka19000  
   2020-12-11 22:28:42 +08:00
@zxCoder #10 “流”不存在一次发一个的概念,流是连续的
misaka19000
    12
misaka19000  
   2020-12-11 22:30:19 +08:00
插一句,在 socket 中最小的单位是 byte,除非你的命令长度固定,不然显然无法保证从 byte 流中解析出你发送的“命令”
zxCoder
    13
zxCoder  
OP
   2020-12-11 22:31:53 +08:00
@misaka19000 只要固定前几个字节发数据长度就可以了 这个应该不是问题
zxCoder
    14
zxCoder  
OP
   2020-12-11 22:32:53 +08:00
@misaka19000 我的意思是客户端 send 一次,这时候服务端不就 receive 到了数据,就可以解析这个命令了,然后返回数据给客户端,客户端接收到数据之后可以输入第二条命令了,再继续 send
misaka19000
    15
misaka19000  
   2020-12-11 22:35:27 +08:00
@zxCoder #14 你在 receive 的时候要指定 receive 多少个字节的
zxCoder
    16
zxCoder  
OP
   2020-12-11 22:42:36 +08:00
@misaka19000 这样的吗 我记得有类似那种事件驱动的 一收到数据就触发
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2351 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 27ms UTC 09:47 PVG 17:47 LAX 01:47 JFK 04:47
Do have faith in what you're doing.
ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86