rust使用tokio读写数据卡死(新手)怎么处理?

作者站长头像
站长
· 阅读数 20

各位老师,我是一个rust新手尝试使用tokio做一些实验。目前碰到一个问题,我模拟了一个客户端client.rs,想要他和服务端server.rs进行通讯。客户端发送一些信息给到服务端,进行处理后再把结果发回来。目前的代码会出现客户端卡死,用try_read看了一下原因是WouldBlock错误,单发送和单接收都正常。一旦像代码中出现发送后再接收就会出问题。能否有大佬解释一下原因,谢谢。

client.rs

use clap::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};
use tokio::{
    io::{AsyncReadExt, AsyncWriteExt},
    net::{TcpSocket, TcpStream},
};

type BoxedError = Box<dyn std::error::Error>;

#[derive(Serialize, Deserialize)]
struct RequestFrame {
    command: String,
    key: String,
    value: Option<String>,
}

impl RequestFrame {
    fn new(command: String, key: String, value: Option<String>) -> RequestFrame {
        RequestFrame {
            command: command,
            key: key,
            value: value,
        }
    }
}

#[derive(Parser, Debug)]
#[command(
    version = "0.0.1",
    author = "haozhang",
    long_about = "this is a self-made redis client"
)]
struct Args {
    #[arg(short, long, value_name = "command")]
    command: Command,

    #[arg(short, long, value_name = "key")]
    key: String,

    #[arg(short, long, value_name = "value")]
    value: Option<String>,
}

#[derive(Debug, Clone, ValueEnum)]
enum Command {
    Get,
    Set,
}

async fn get_stream() -> Result<TcpStream, BoxedError> {
    let addr = "127.0.0.0:6379".parse().unwrap();

    let socket = TcpSocket::new_v4().unwrap();
    let stream = socket.connect(addr).await.unwrap();

    Ok(stream)
}

#[tokio::main]
async fn main() -> Result<(), BoxedError> {
    // let args = std::env::args().collect::<Vec<String>>();

    let mut stream = get_stream().await?;

    let (mut reader, mut writer) = stream.split();

    let args = Args::parse();

    let command = match args.command {
        Command::Get => "get".to_string(),
        Command::Set => "set".to_string(),
    };
    let key = args.key;
    let value = args.value;

    // println!("{:?}", command);
    // println!("{:?}", key);
    // println!("{:?}", value);

    let request = RequestFrame::new(command, key, value);

    let request_json_string = serde_json::to_string(&request)?;

    writer.write_all(request_json_string.as_bytes()).await?;
    writer.flush().await?;

    let mut buf = String::new();
    reader.read_to_string(&mut buf).await?;
    // let mut buf = [0; 100];
    // reader.try_read(&mut buf)?;
    println!("{:?}", buf);

    println!("done");

    Ok(())
}

server.rs

use tokio::{
    io::{AsyncReadExt, AsyncWriteExt},
    net::TcpListener,
};

type BoxedError = Box<dyn std::error::Error>;

#[tokio::main]
async fn main() -> Result<(), BoxedError> {
    let listener = TcpListener::bind("0.0.0.0:6379").await?;

    println!("listening on {}", listener.local_addr()?.port());

    loop {
        let (socket, _) = listener.accept().await?;

        tokio::spawn(async {
            match process(socket).await {
                Ok(()) => (),
                Err(e) => eprintln!("process occurs an error: {e}")
            };
        });
    }
}

async fn process(mut socket: tokio::net::TcpStream) -> Result<(), BoxedError> {
    let (mut reader, mut writer) = socket.split();

    let mut buf = String::new();

    reader.read_to_string(&mut buf).await?;

    writer.write_all("we got the command, thanks".as_bytes()).await?;

    writer.flush().await?;

    println!("content: {}", buf);

    Ok(())
}
回复
1个回答
avatar
test
2024-06-19

用错方法了,server中的read_to_string是通过EOF作为结束标志的,这个一般是操作文件的。这里需要通过read方法手动拼接结果

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容