如果客户端和服务端是同步串行的 socket 通信,是不是不用考虑粘包的问题了
就客户端发一个命令,服务端接收处理后发送回复,客户端收到回复,再发送下一个命令
1
CEBBCAT 2020-12-11 18:15:54 +08:00 1
等一个
|
3
3dwelcome 2020-12-11 18:45:32 +08:00
参考 websocket 协议,必须有包长度。
tcp/ip 强制把流切成一个个小包,是物理层需要。而你 IP 包的发送,必然会存在发送失败,导致过一会儿客户端重发的情况存在。 网络没有 100%的可靠性。所以你程序要健壮,就别假收到的 TCP 包是完整的,能直接处理,多做协议设计才是正途。 |
4
Foxkeh 2020-12-11 18:57:24 +08:00
是的, 我们公司有类似场景, 就是这么干的, 注意留校验位.
|
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 字节) |
6
whileFalse 2020-12-11 20:10:57 +08:00
回复 LZ 的问题。如果你一次只发一个包,过很久才发第二个,那肯定不会粘包。但你要注意自己的包大小,如果超过 1500,那会遇到拆箱问题。万一网络一卡 你先收到第一个箱,第二个箱还没到你就去处理数据了,那也会有问题。
|
7
misaka19000 2020-12-11 20:11:20 +08:00
你怎么知道客户端发的是不是一个命令
|
8
zxCoder OP @misaka19000 假设的情况啊 客户端发一个命令之后要等待回复才能输入第二个命令,这种场景很常见吧
|
9
misaka19000 2020-12-11 22:15:41 +08:00
@zxCoder #8 socket 是流,你没法判断一个命令是开始还是结束了
|
10
zxCoder OP @misaka19000 可是我一次只发一个命令 也不行吗
|
11
misaka19000 2020-12-11 22:28:42 +08:00
@zxCoder #10 “流”不存在一次发一个的概念,流是连续的
|
12
misaka19000 2020-12-11 22:30:19 +08:00
插一句,在 socket 中最小的单位是 byte,除非你的命令长度固定,不然显然无法保证从 byte 流中解析出你发送的“命令”
|
13
zxCoder OP @misaka19000 只要固定前几个字节发数据长度就可以了 这个应该不是问题
|
14
zxCoder OP @misaka19000 我的意思是客户端 send 一次,这时候服务端不就 receive 到了数据,就可以解析这个命令了,然后返回数据给客户端,客户端接收到数据之后可以输入第二条命令了,再继续 send
|
15
misaka19000 2020-12-11 22:35:27 +08:00
@zxCoder #14 你在 receive 的时候要指定 receive 多少个字节的
|
16
zxCoder OP @misaka19000 这样的吗 我记得有类似那种事件驱动的 一收到数据就触发
|