请教: WebSocket + Protobuf 做服务,如何定义路由 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
uiosun
V2EX    Web Dev

请教: WebSocket + Protobuf 做服务,如何定义路由

  •  
  •   uiosun 2024-05-19 11:08:08 +08:00 3564 次点击
    这是一个创建于 564 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题:

    目前在项目中采用 WebSocket 长连接做服务,Protobuf 作为请求/响应的数据结构。

    当存在多个路由时,如何定义它们呢?

    举个例子:聊天室

    接口 1:(按条件)筛选聊天内容 接口 2:发送消息

    请教各位,长连接服务在这种场景,如何与客户通讯(怎么定义路由,或者如果不定义,有什么其他办法吗?)

    谢谢各位!


    背景:我对于 Protobuf 、长连接的使用经验比较匮乏,之前只做过 HTTP/RPC + Protobuf 的项目。

    我的思路历程:

    最简单的就是 Protobuf 封装一个标准路由结构:

    message IRoute { string key = 1; string jsOnRes= 2; } 

    key 做路由键,jsonRes 就是 JSON 字符串,只有响应时才返回纯 Protobuf 对象,但这就买椟还珠了吧?(不如直接用 JSON )

    后面又想定义 Interface 来设计,先将数据转化为标准对象,然后判断 key 来将数据转化为实际路由,但对二进制数据,我做不到只转化部分内容……

    最后,目前打算使用 text 作为路由,自己手动分割,然后响应时返回 Protobuf 对象。

    ryc111
        1
    ryc111  
       2024-05-19 12:55:00 +08:00
    用 grpc 定义两个 service?
    InDom
        2
    InDom  
       2024-05-19 13:28:25 +08:00   1
    | ver | route id | body len | body |

    然后 body 才是你的 Protobuf 结构。

    或者

    | ver | route len | route str | body len | body |
    uiosun
        3
    uiosun  
    OP
       2024-05-19 15:30:58 +08:00
    @ryc111 那就太多了哈哈,我打算写个游戏,玩家的动作会比较多

    @InDom 谢谢大佬!再请教一下,`|...|...|` 的结构,是个 Request 对象?就是:

    再给 request.Body 赋予 Protobuf 的对象,最后将整个对象打包成二进制,发给 Client 。
    cloud107202
        4
    cloud107202  
       2024-05-19 18:16:31 +08:00   1
    抛弃路由的概念,用 pb 定义消息结构就好。举个例子

    message FetchChatHistoryRequest(id, count, start, end, e.g.)
    message FetchChatHistoryResponse(repeat string xxx)
    message SendChatMsg(string target, string content)

    在实现里收到消息,解析类型,派发给对应 Type 的逻辑做业务逻辑处理,他们的逻辑当是独立离散的。
    理解这一层之后,收发两端都有个需要,就是识别一个 raw bytes 比如 Java 语言会接收到 byte[] 作为消息包,要知道它具体是什么。 这里有两种思路: 第一是像二楼这样,外层用 TCP 的 TV 或 TLV 来包装一下,就是 type-length-value 这种。前两个字段一定要定长,比如 type 是 4byte 的数字类型,自己给上述消息定义好类型 id 。lenght 是 8byte 的长整形,数值是后面 value 部分的长度。value 里就是 pb 消息,encoded pb bytes 。 自己写个简单的 encoding / decoding 逻辑
    cloud107202
        5
    cloud107202  
       2024-05-19 18:22:06 +08:00   1
    第二种是直接用 pb 的高阶用法,oneof 字段。参考这里 https://zhuanlan.zhihu.com/p/453913153 例子,可以避开对 bytes 的 raw byte manipulation. 有兴趣研读 pb 文档的话,我推荐第二种
    cloud107202
        6
    cloud107202  
       2024-05-19 18:25:56 +08:00   1
    针对你的困扰出发,核心就是这也许是你头一次针对 websocket 场景编程。这里跟 HTTP 的语义封装没关系,尤其是没有请求-响应的通讯模式,没有路由的概念。先定义消息类型(完全由你自行定义),把消息发跟收分开处理就好,各自独立
    kiracyan
        7
    kiracyan  
       2024-05-19 21:43:33 +08:00   1
    建议用 2 个 key 区分功能 内容用 bytebuff
    Nazz
        8
    Nazz  
       2024-05-19 21:48:03 +08:00 via Android
    在消息头用两个字节(uint16)标识路由
    Nazz
        9
    Nazz  
       2024-05-19 21:53:56 +08:00 via Android   2
    用字符串标识路由更好些,开头的两个字节表示路由长度. ws 库可以使用 gws, 它的 payload 是 bytes.buffer 类型.
    sunny352787
        10
    sunny352787  
       2024-05-19 22:20:11 +08:00 via Android   1
    对于你的技术储备,我建议直接 grpc 最省事,有切割二进制流的功夫 grpc 写好多功能了
    kuanat
        11
    kuanat  
       2024-05-19 22:23:30 +08:00 via Android   1
    这种通信场景一般没有路由的说法吧,都是用协议这个词。

    如楼上说得都挺好了。我有个建议,你可以看看用 unix domain socket 做 IPC 通信一般是怎么做的。ws 就是把本地变远程,protobuf 就是 socket 的具体实现(协议/路由)。

    在 web 编程里是匹配路由然后把请求交给对应的 handler ,在 socket 编程里硬要说路由或者协议的话就是某个字节代表特定的类型,然后每个类型有一个专门的 handler 来响应。
    gamexg
        12
    gamexg  
       2024-05-19 22:59:57 +08:00   2
    路由简单,
    如前面回复,在包内容前面加点路由字段就行.

    但是其他麻烦还有很多,
    计划是否允许并行请求(前一个接口 1 请求未响应就发送新的接口 2 请求)?
    如果允许并行请求,那么能处理响应顺序和请求顺序不一致吗?

    另一个情况,比如发送消息,第一个消息还没返回响应,第二个消息又发送了. 那么之后收到的响应可能是第一个也可能是第二个的响.虽然加个 id 也能处理,但是加上超时/连接断开重发请求等情况会很麻烦.


    自己去实现这些很麻烦.
    uiosun
        13
    uiosun  
    OP
       2024-05-20 11:35:59 +08:00
    @cloud107202 @kiracyan @Nazz @kuanat 谢谢大佬们,你们好强!

    @gamexg @sunny352787 也谢谢两位大佬,你们也好强!这个项目是学点新东西,所以不介意费事。

    我先读读 gRPC 流的知识,看能不能快速实现我的需求。再次感谢各位!
    Nazz
        14
    Nazz  
       2024-05-20 11:50:36 +08:00   2
    做 IM 应该用 WebSocket 而不是 gRPC Stream, io.Reader 切割二进制流很简单的, 发送成功确认做起来麻烦些
    Nazz
        15
    Nazz  
       2024-05-20 11:51:40 +08:00
    对性能没有高要求的话应该使用 JSON
    Nazz
        16
    Nazz  
       2024-05-20 11:52:19 +08:00
    或者 MsgPack
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5247 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 08:43 PVG 16:43 LAX 00:43 JFK 03:43
    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