36|阶段实操(4):构建一个简单的KV server-网络处理
陈天
该思维导图由 AI 生成,仅供参考
你好,我是陈天。
经历了基础篇和进阶篇中两讲的构建和优化,到现在,我们的 KV server 核心功能已经比较完善了。不知道你有没有注意,之前一直在使用一个神秘的 async-prost 库,我们神奇地完成了 TCP frame 的封包和解包。是怎么完成的呢?
async-prost 是我仿照 Jonhoo 的 async-bincode 做的一个处理 protobuf frame 的库,它可以和各种网络协议适配,包括 TCP / WebSocket / HTTP2 等。由于考虑通用性,它的抽象级别比较高,用了大量的泛型参数,主流程如下图所示:
主要的思路就是在序列化数据的时候,添加一个头部来提供 frame 的长度,反序列化的时候,先读出头部,获得长度,再读取相应的数据。感兴趣的同学可以去看代码,这里就不展开了。
今天我们的挑战就是,在上一次完成的 KV server 的基础上,来试着不依赖 async-prost,自己处理封包和解包的逻辑。如果你掌握了这个能力,配合 protobuf,就可以设计出任何可以承载实际业务的协议了。
如何定义协议的 Frame?
protobuf 帮我们解决了协议消息如何定义的问题,然而一个消息和另一个消息之间如何区分,是个伤脑筋的事情。我们需要定义合适的分隔符。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了如何构建一个简单的KV server,并重点讲解了网络处理的相关内容。作者首先介绍了async-prost库的使用,然后挑战读者在不依赖async-prost的情况下,自己处理封包和解包的逻辑。接着讲解了如何定义协议的Frame,以及使用tokio-util库来处理和frame相关的封包解包的主要需求。最后给出了一个示例代码,展示了如何使用tokio-util库来构建一个简单的KV server。通过本文的学习,读者可以了解到如何处理网络通信中的封包和解包逻辑,以及如何使用tokio-util库来简化网络处理的代码。文章还介绍了如何处理gzip压缩以及如何实现Frame的序列化和反序列化,并通过测试验证了其正确性。文章内容涉及网络通信、异步处理和数据结构实现等方面,对于想要深入了解网络开发的读者来说,具有很高的参考价值。文章还提出了一些思考题,引导读者深入思考和探讨相关技术问题。同时,还介绍了如何在生产环境中运行的代码,都要求至少有80%以上的测试覆盖率,并提出了一些关于测试覆盖率的建议。整体而言,本文内容丰富,涵盖了网络开发的多个方面,对于想要深入了解Rust下网络开发的读者具有很高的参考价值。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》,新⼈⾸单¥68
《陈天 · Rust 编程第一课》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(6)
- 最新
- 精选
- 罗杰越来越接近实际工作了,老师特别用心,目前没找到网络这块讲解这么详细的内容了。
作者回复: :)
2021-11-232 - 荒野林克老师,代码里当 frame 刚好是 2G 时,按理说应该已经越界了吧?
作者回复: 对,确实如此。多谢指正。
2021-12-171 - Rex WangGitHub代码里36_kv/src/error.rs中,KvError去掉了PartialEq属性宏,这是因为std::io::Error不支持binary操作符。 为了保证之前的test依然有效,可以自己定义一个IoError替换原文中KvError中的std::io::Error,手动实现impl From<std::io::Error> for KvError。2022-08-19归属地:北京4
- 乌龙猹内容夯实 思路清晰 结构完整 循序渐进 每周都期待着老师更新课程内容2021-11-223
- 进击的Lancelot思考题 1: 如果要压缩方式需要同时支持 gzip、lz4、zstd 这三种,则需要 2bit 的标记位,00 表示不压缩、01 表示 gzip、10 表示 lz4、11 表示 zstd,同样也是提取出一个 compressor 的 trait 并针对不同的压缩算法实现相应的 compress 和 decompress 方法,具体可以参考我的代码仓库:https://github.com/Phoenix500526/simple_kv/blob/main/src/network/compress 下的文件 思考题 2: 我采用了 shellfish 实现了 simple-kv-cli,代码可以参考:https://github.com/Phoenix500526/simple_kv/blob/main/src/kvc-cli.rs2022-10-13归属地:广东2
- sonald``` /// 从 stream 中读取一个完整的 frame pub async fn read_frame<S>(stream: &mut S, buf: &mut BytesMut) -> Result<(), KvError> where S: AsyncRead + Unpin + Send, { let header = stream.read_u32().await? as usize; let (len, _compressed) = decode_header(header); // 如果没有这么大的内存,就分配至少一个 frame 的内存,保证它可用 buf.reserve(LEN_LEN + len); buf.put_u32(header as _); // advance_mut 是 unsafe 的原因是,从当前位置 pos 到 pos + len, // 这段内存目前没有初始化。我们就是为了 reserve 这段内存,然后从 stream // 里读取,读取完,它就是初始化的。所以,我们这么用是安全的 unsafe { buf.advance_mut(len) }; stream.read_exact(&mut buf[LEN_LEN..]).await?; Ok(()) } ``` 这里最后面的read_exact参数是有问题的吧,假设连续两次调用read_frame而没有消费buf的话,应该改成下面这样? ``` let start = len - size; stream.read_exact(&mut buf[start..]).await?; ```2023-01-17归属地:北京
收起评论