使用Serde从套接字反序列化换行符分隔的JSON

时间:2017-11-06 21:28:16

标签: rust deserialization serde

我正在尝试使用serde将JSON结构从客户端发送到服务器。从客户端到服务器的换行符表示套接字已完成。我的服务器看起来像这样

#[derive(Serialize, Deserialize, Debug)]
struct Point3D {
    x: u32,
    y: u32,
    z: u32,
}

fn handle_client(mut stream: TcpStream) -> Result<(), Error> {
    println!("Incoming connection from: {}", stream.peer_addr()?);
    let mut buffer = [0; 512];
    loop {
        let bytes_read = stream.read(&mut buffer)?;
        if bytes_read == 0 {
            return Ok(());
        }
        let buf_str: &str = str::from_utf8(&buffer).expect("Boom");
        let input: Point3D = serde_json::from_str(&buf_str)?;
        let result: String = (input.x.pow(2) + input.y.pow(2) + input.z.pow(2)).to_string();
        stream.write(result.as_bytes())?;
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() != 2 {
        eprintln!("Please provide --client or --server as argument");
        std::process::exit(1);
    }
    if args[1] == "--server" {
        let listener = TcpListener::bind("0.0.0.0:8888").expect("Could not bind");
        for stream in listener.incoming() {
            match stream {
                Err(e) => eprintln!("failed: {}", e),
                Ok(stream) => {
                    thread::spawn(move || {
                        handle_client(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
                    });
                }
            }
        }
    } else if args[1] == "--client" {
        let mut stream = TcpStream::connect("127.0.0.1:8888").expect("Could not connect to server");
        println!("Please provide a 3D point as three comma separated integers");
        loop {
            let mut input = String::new();
            let mut buffer: Vec<u8> = Vec::new();
            stdin()
                .read_line(&mut input)
                .expect("Failed to read from stdin");
            let parts: Vec<&str> = input.trim_matches('\n').split(',').collect();
            let point = Point3D {
                x: parts[0].parse().unwrap(),
                y: parts[1].parse().unwrap(),
                z: parts[2].parse().unwrap(),
            };
            stream
                .write(serde_json::to_string(&point).unwrap().as_bytes())
                .expect("Failed to write to server");

            let mut reader = BufReader::new(&stream);

            reader
                .read_until(b'\n', &mut buffer)
                .expect("Could not read into buffer");
            print!(
                "{}",
                str::from_utf8(&buffer).expect("Could not write buffer as string")
            );
        }
    }
}

如何在读取字符串之前知道要分配的缓冲区长度?如果我的缓冲区太大,则serde无法反序列化它,并显示错误消息,表示存在无效字符。有更好的方法吗?

1 个答案:

答案 0 :(得分:3)

TcpStream放入BufReader。这允许您读取特定字节(在本例中为换行符)。然后,您可以使用Serde:

解析读取的字节
use std::io::{BufRead, BufReader};
use std::io::Write;

fn handle_client(mut stream: TcpStream) -> Result<(), Error> {
    let mut data = Vec::new();
    let mut stream = BufReader::new(stream);

    loop {
        data.clear();

        let bytes_read = stream.read_until(b'\n', &mut data)?;
        if bytes_read == 0 {
            return Ok(());
        }

        let input: Point3D = serde_json::from_slice(&data)?;
        let value = input.x.pow(2) + input.y.pow(2) + input.z.pow(2);

        write!(stream.get_mut(), "{}", value)?;
    }
}

重新使用data的分配,我有点想象,这意味着在每个循环开始时重置缓冲区非常重要。我也避免为结果分配内存,只是直接打印到输出流。