rust实践-异步并发socket通信

客户端

rust 复制代码
[package]
name = "rust_client"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.14.0", features = ["full"] }
rust 复制代码
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> io::Result<()> {
    let mut stream = TcpStream::connect("127.0.0.1:7878").await?;
    let (mut rd, mut wr) = stream.split();

    let mut buf = vec![0; 1024];
    loop {
        let n = match rd.read(&mut buf).await {
            Ok(n) if n == 0 => {
				println!("read zero data, finish");
				return Ok(());
			}
            Ok(n) => {
				let msg = String::from_utf8_lossy(&buf[..n]).to_string();
				println!("read {} bytes'data : {}", n, msg);
				n
			}
            Err(e) => {
                println!("failed to read from socket; err = {}", e);
                return Err(e);
            }
        };
        match wr.write_all(&buf[0..n]).await {
            Ok(_) => {
				println!("write data to server success");
				()
			}
            Err(e) => {
                println!("failed to write to socket; err = {}", e);
                return Err(e);
            }
        }
        wr.flush().await?;
    }
}

服务端

rust 复制代码
[package]
name = "rust_server"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.14.0", features = ["full"] }
rust 复制代码
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:7878").await?;

    loop {
        let (mut stream, _) = listener.accept().await?;
		tokio::spawn(async move {
            let (mut rd, mut wr) = stream.split();
			println!("read and write socket spilt success");
			let data = "Hello, world!\n";
			wr.write_all(data.as_bytes()).await;
			println!("write data success");

    		let mut buf = vec![0; 1024];
    		match rd.read(&mut buf).await {
        		Ok(n) => {
            		let msg = String::from_utf8_lossy(&buf[..n]);
            		println!("read data : {}", msg);
        		},
        		Err(e) => eprintln!("Failed to read from socket; err = {}", e),
   			}
        });
	}
}

附录

from_utf8_lossy

String::from_utf8_lossy() 函数将字节数组转换为字符串

接受一个字节数组作为参数,并尝试将其转换为 UTF-8 编码的字符串

如果字节数组包含无效的 UTF-8 字符,则这些字符将被替换为问号 ?

from_utf8_lossy() 函数返回一个 Cow 类型的对象

这个对象实现了 ToString trait

所以可以使用 to_string() 方法将其转换为 String 类型的字符串

如果字节数组的长度很大,这个函数还可以使用 &str 类型来节省内存

Cow

Cow 是一个"借用或拥有(borrow or own)"字符串类型

其中的 Cow 是"借用或拥有(borrow or own)"的缩写。

它的定义如下:

rust 复制代码
pub enum Cow<'a, B>
where
    B: 'a + ToOwned + ?Sized,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

在 Rust 中,字符串通常采用 String 或 &str 两种类型。

String 类型是一个可变的字符串类型,实际内容被存储在堆上,并且拥有内存所有权。

&str 类型是一个不可变的字符串切片类型,它的实际内容被存储在其他地方,比如堆上或者栈上,并且不拥有内存所有权。

Cow 类型可以用于同时支持 String 和 &str 两种类型。它的第一个泛型参数 'a 用于指定借用的生命周期,可以是任意标识符,表示 'a 参数对类型的所有权没有影响。第二个泛型参数 B 是一个类型参数,用于指定实际的数据类型。

在 Cow 中,Borrowed(&'a B) 表示借用另一个类型 B 的内容,而 Owned(::Owned) 表示拥有 B 类型的所有权。
如果 B 类型已经拥有内存所有权,则返回 Owned 类型,否则返回 Borrowed 类型。
这使得 Cow 类型在不需要分配内存的情况下,可以支持可变类型和不可变类型的字符串。

相关推荐
云飞云共享云桌面21 小时前
10个SolidWorks研发设计共享一台工作站——昆山精密机械工厂降本增效一举三得
网络
云上漫步者1 天前
深度实战:Rust交叉编译适配OpenHarmony PC——unicode_width完整适配案例
开发语言·后端·rust·harmonyos
Bruce_Liuxiaowei1 天前
SSH主机密钥验证失败(Host key verification failed)深度解析与解决方案
运维·网络·ssh
想你依然心痛1 天前
AI赋能编程语言挑战赛:从Python到Rust,我用AI大模型重塑开发效率
人工智能·python·rust
星瞰物联1 天前
融合北斗与天通卫星通信技术的堤坝水文监测卫星图传系统
网络·物联网·安全·系统架构
周杰伦_Jay1 天前
【GRPC 和 HTTP】设计目标和底层实现
网络·网络协议·http
木子欢儿1 天前
Prometheus Blackbox域名SSL证书监控并设置AlertManager告警
网络·网络协议·ssl·prometheus
猫天意1 天前
【即插即用模块】AAAI2025 | 高频 + 空间感知!新 HS-FPN 让“极小目标”不再消失!SCI保二区争一区!彻底疯狂!!!
网络·人工智能·深度学习·学习·音视频
草根站起来1 天前
SSL证书根证书没有二级根证书、三级根证书、四级根证书,SSL证书参数诈骗被迫使用了套牌贴牌非原厂SSL和证书
网络·网络协议·ssl
谢尔登1 天前
HTTP 协议组成
网络·网络协议·http