Rust 语言从入门到实战
唐刚
Rust 语言中文社区联合创始人
5266 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 36 讲
Rust 语言从入门到实战
15
15
1.0x
00:00/00:00
登录|注册

14|tokio实战:编写一个网络命令行程序

你好,我是 Mike,上一节课我们了解了 Rust 异步编程和 tokio 的基础知识,今天我们就来一起用 tokio 做一个小应用。

准备阶段

我们常常需要知道远程服务器上的一些信息,这有一些现成的工具可以做到。我们来试一下如何使用 tokio 实现这一功能。
目标:编写一个获取服务器时间的命令行程序。
任务分解:
命令行:这个工具取名为 getinfo, 参数格式是 getinfo {ip},就是在 getinfo 后接 IP 地址,获取服务器时间。
tcp server:监听 8888 端口,获取从客户端来的请求,然后获取服务器本地时间,返回。
tcp client:连接服务端地址 ip:port,向服务端发送获取服务器时间指令。
测试。

实现

下面我们开始实现。

创建项目

我们打开终端或者 IDE 中的 Terminal,执行:
cargo new --bin getinfo

命令行雏形

Rust 标准库中实际已经有获取命令行参数的功能,std::env 提供了一种获取命令行参数的方法 std::env::args(),可以将命令行参数转换成一个迭代器,通过 for 循环就可以遍历所有命令行参数,当然也可以使用迭代器上的 .nth() 直接定位到某一个参数。比如:
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8888".to_string());
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

使用Rust语言和tokio库编写网络命令行程序是本文的主题。文章首先介绍了准备阶段,包括任务分解和命令行雏形的实现。接着详细讲解了如何创建项目和获取命令行参数。然后,文章介绍了如何基于tokio实现tcp server,包括添加依赖和具体的代码实现。通过解释代码中的细节,读者可以了解如何接收tcp client的连接、读取指令数据、获取服务器本地时间信息并将信息返回给客户端。整体而言,本文通过实际代码示例和详细解释,帮助读者快速了解了使用tokio库编写网络命令行程序的过程。 此外,文章还介绍了Frame层的概念和tokio提供的多种编解码类型,帮助开发者处理网络数据流,使得读取和处理数据更加方便和高效。通过讲解Frame层的概念和编解码类型,读者可以理解如何利用tokio框架处理网络数据流的复杂性。 总的来说,本文通过实际示例和详细解释,帮助读者了解了使用tokio库编写网络命令行程序的过程,并介绍了如何利用Frame层处理网络数据流的复杂性。读者可以从中学习到如何利用Rust语言和tokio库进行网络编程,以及如何处理网络数据流的相关技术。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Rust 语言从入门到实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(12)

  • 最新
  • 精选
  • PEtFiSh
    EOF: End of file. 在linux万物皆file的情况下connection也可以是一个file。所以,当Connection关闭的时候,就会产生EOF。 stream.read_to_end()是持续read()直到EOF,因此能够读完网络里的数据,如果使用stream.read_to_end(&mut buf).await?;读取的话,会持续wait,直到连接关闭才能进行后续的操作。

    作者回复: 👍,真棒!

    2023-11-20归属地:四川
    2
  • 学水
    感觉这部分内容和java的netty包有点像

    作者回复: 对的,其实网络编程到了底层基本都是这个样子了。

    2023-11-20归属地:加拿大
    2
    2
  • Citroen
    这段代码 let mut framed_stream = Framed::new(stream, LengthDelimitedCodec::new()) 请问一下老师,我现在需要接收client端的数据(数据是打包好的protobuf序列化后的二进制数据, 前面有四位长度表示这个序列化后的二进制数据的长度,也就是说数据格式是,头(四位 用于说明后面完整protobuf序列化后的数据长度)加内容(protobuf序列化后的二进制数据),len(四位长度)加main(protobuf序列化后的二进制数据 每次长度不固定,但可通过前面的len可以知道),每段数据都是这样 这样的数据怎么取?

    作者回复: 很简单,发送端用 LengthDelimitedCodec 编码的,接收端也同样用 LengthDelimitedCodec 解码就行了。tokio的这层Framed包装自动完成了这项工作了,具体的编解码是在下层layer做的,上层你就关心业务就好啦,已经给你取到了。

    2023-11-24归属地:辽宁
    3
    1
  • 哄哄
    应该用什么已有的crate包,感觉也是新人的一个问题。请问上哪能快速认识常用第三方包呢?

    作者回复: crates.io, lib.rs, https://github.com/rust-unofficial/awesome-rust

    2023-11-20归属地:北京
    1
  • 沉默的话唠
    跟着一路下来,感觉讲师讲的真的不错。 不知道后面考不考虑有训练营之类的,更加全面体系的课程。

    作者回复: 感谢肯定🙏,回头和小编商量商量。

    2023-12-28归属地:广西
  • superggn
    EOF => End Of File, 在数据流断开的时候会碰到 stream.read_to_end(buf) => 把这个 stream 里接收到的所有数据都丢到一个 buf_vec 里, 应该是一个阻塞函数吧, 只要链接不断开, 就一直等待, 单开一个进程 / 线程来跑 read_to_end 然后在别的进程 / 线程从 buf 里往外面读数据 不过感觉如果用 read_to_end 的话当前 stream 就没办法往里写数据了, 这咋整啊, 难道是 clone 一份 stream 然后在其他进程 / 线程来写吗, 还是设计的时候就不考虑往 `用了 read_to_end 的 stream`里继续写数据了?

    作者回复: tokio strean是全双工的,可以写。但是你如果程序被卡在 read_to_end 那里,那写逻辑也执行不了。

    2023-12-21归属地:北京
  • superggn
    啊? 有源码的啊, star 一下先

    作者回复: https://github.com/miketang84/jikeshijian/

    2023-12-21归属地:北京
  • -Hedon🍭
    思考题1:EOF EOF 是 "End of File" 的缩写,意为“文件结束”。它是一个用于表示文件或数据流末尾的控制信号或字符。当读取文件或数据流时,EOF用于指示没有更多的数据可读取。 EOF 通常出现在以下几种情况: 1. 文件读取:在读取文件内容时,到达文件末尾后,会遇到 EOF。这告诉程序没有更多的数据可读取。 2. 标准输入:在某些编程语言或环境中,如 Unix/Linux 的命令行,可以使用特定的键盘组合(如 Ctrl+D )来生成 EOF 信号,表示标准输入结束。 3. 数据流结束:在处理数据流(如网络传输中的数据)时,EOF 可以用来指示数据传输已经完成。 思考题2:stream.read_to_end() 首先我觉得核心点在 “读完” 这个概念上,即意味着连接中的数据是有限的,才有读完,如果是无限的流数据,那么 stream.read_to_end() 会一直阻塞等待数据的到来。如果明确数据的有限的,那么在数据源发出 EOF 后,stream.read_to_end() 就会返回,那这个时候是可以 “读完” 的。当前,前提是你的内存得够。 (连续2周搬砖赶需求,终于能抽点时间续上 rust 的学习了 T_T)

    作者回复: 👍,不错。

    2023-12-20归属地:湖北
  • A0.何文祥
    cargo new --bin getinf应为cargo new --bin getinfo

    编辑回复: 再次感谢🤝

    2023-11-20归属地:广东
  • Andylinge
    Windows 11 报如下错误,大家可以把process里面的获取时间命令自己用Rust重写一下。 ```Listening on: 127.0.0.1:8880 Accepted a connection from: 127.0.0.1:9354 gettime thread 'tokio-runtime-worker' panicked at src/server.rs:80:58: called `Result::unwrap()` on an `Err` value: Error { kind: NotFound, message: "program not found" } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: process didn't exit successfully: `D:\00-Program\05-Rust\14-Rust_MikeTang\r14_tokio\getinfo\target\debug\server.exe` (exit code: 0xc000013a, STATUS_CONTROL_C_EXIT) ```

    作者回复: 对的,date命令是linux下的,抱歉忘了这个细节,后面想办法补充说明一下。

    2023-11-20归属地:江苏
    2
收起评论
大纲
固定大纲
准备阶段
实现
创建项目
命令行雏形
显示
设置
留言
12
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部