做消息推送服务器,自己设计了一套私有协议。
但是有一个问题。传统的 http 是一应一答的,消息推送是长链接的,如果客户端不按照规定的协议格式来传输数据,就会导致服务器端无法正常解析数据。
因为拆包粘包的问题,一旦缓冲区的部分数据异常,那么后边数据就会全部出错都无法解析(因为缓冲区的数据都是连续的,根据特定字节长度来读取字段数据:readInt/readLong/readChar 等)。
那么出现这样的错误数据无法解析,服务器端应该如何处理呢?
我的想法是,一个消息协议以某个特殊字符串开头(如:$^&* ),当服务器数据解析出错时,那么就把错误的数据全部 discard ,直到遇到下一个“$^&*”为止。
1
morethansean 2015-10-21 12:48:24 +08:00
程序不出错,缓冲区不会数据异常吧。
|
2
sujin190 2015-10-21 13:28:03 +08:00
关闭连接让客户端重新打开就是了,省得这么麻烦
|
4
broadliyn OP @morethansean 就怕有异常。
|
5
skydiver 2015-10-21 13:58:05 +08:00
TCP 本来就是流协议,需要自己设定包的边界。
|
6
hyq 2015-10-21 13:59:40 +08:00
把一个包定义成[length]和[body],先读取 length ,然后根据 length ,读取 body 。
|
7
hyq 2015-10-21 14:00:46 +08:00
如果怕客户端乱来,可以加个 checksum 或者来个加密后再 checksum
|
8
broadliyn OP @hyq 我现在的协议类似 http ,有 header (定长)和 body (变长)两部分, header 里带了 timestamp 、 body 的 length 、 body 的 checksum ,然后根据 length 去取剩余变长的 body 部分。
现在主要是怕因为客户端乱来等原因, body 部分丢了一半,但是服务端解析的时候为了读取 body ,会把下一个协议消息包当成当前 body 给读进去,导致后边所有的包全乱了。 因此我想解决的是如何比较优雅的处理当前异常消息包而尽量减少对后边消息的影响 |
9
hyq 2015-10-21 14:37:30 +08:00
@broadliyn 客户端自己发错了,怎么能保证接下来的数据没有错误?比如第一个请求是创建一个资源,第二个请求是对资源进行操作。第一个请求出错了,资源没有创建。第二个请求也不应该去执行吧。
|
11
morethansean 2015-10-21 14:40:33 +08:00
@broadliyn 异常除非别人修改了客户端的代码,然后发一些异常,不然按照你写的程序,严格按照你的协议生成的包,哪来的异常啊?有了那样的异常直接断开链接让重连。
|
13
wy315700 2015-10-21 15:21:08 +08:00
加校验
|
14
gamexg 2015-10-21 15:45:04 +08:00
有 checksum ,识别到了错误就直接关闭连接。
封装一个打包和解包,所有对 stream 的操作都经过这两个函数,就很难出现错误了。 |
15
xierch 2015-10-21 16:12:34 +08:00 2
…… 请重新学习 TCP
|
17
register 2015-10-21 17:30:10 +08:00 1
TCP 是流协议,不存在你说的粘包问题。上层定义的 Packet 可能被 TCP 分成多次发送;多个 Packet 也可能被一次发送,这种情况可能就是你说的"粘包"。
|
18
ipconfiger 2015-10-21 17:49:54 +08:00
LZ 说的已经不是粘包的问题了,而是解决客户端写错了给别人擦屁股的问题,无解,解析出错就报错就行了
|
19
inevermore 2015-10-21 20:20:46 +08:00 1
既然是长连接,那么当客户端传来的报文错误,直接断开就可以,然后让客户端重练就可以
|
20
inevermore 2015-10-21 20:21:15 +08:00 1
@register 虽然『粘包』是个伪命题,但是一般都这么说。
|
21
qq286735628 2015-10-21 20:40:33 +08:00 via iPhone
消息推送? BS 架构可以直接用 SSE ,对于不支持 EventSource 的浏览器,可以很容易用 HTTP 降级处理。
|
22
broadliyn OP @register 谢谢,其实主要这里是我没有找到一个合适的说明方式。
准确的说应该是 tcp 是流协议,其中一个 packet 数据出错可能会影响后续的 packet 数据。。 |
23
broadliyn OP @inevermore 非常感谢!
|
24
int64ago 2015-10-22 00:34:06 +08:00 via Android
每个消息都有固定头尾格式的话,其实一个轮询+正则就搞定了
|
25
wind4 2015-10-22 07:21:36 +08:00
TCP 自带校验,不会出现丢包,也就不会出现解包错误。
|