rust - 使用 rust serde 反序列化请求和响应

标签 rust serde

我正在尝试在服务器/客户端反/序列化请求和响应。以下是我尝试过的内容:-

use std::collections::HashMap;
use std::fmt;
use std::io::prelude::*;
use std::net::TcpStream;

use serde_derive::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct Address {
    street: String,
    city: String,
    country: String,
}

#[derive(Serialize, Deserialize)]
enum Gender {
    Male,
    Female,
}

// #[derive(Debug)] does this internally.
impl fmt::Debug for Gender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Gender::Male => write!(f, "M"),
            Gender::Female => write!(f, "F"),
            _ => write!(f, "U"),
        }
    }
}

#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)]
enum Level {
    SSC,
    HSC,
    Graduation,
}

impl fmt::Debug for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Level::SSC => write!(f, "SSC"),
            Level::HSC => write!(f, "HSC"),
            Level::Graduation => write!(f, "Graduation"),
            _ => write!(f, "Unknown"),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct Person {
    ssn: String,
    age: u16,
    name: String,
    gender: Gender,
    contacts: Vec<String>,
    address: Address,
    education: HashMap<Level, i32>,
}

#[derive(Serialize, Deserialize, Debug)]
enum Message {
    Request { ssn: String },
    Response(Person),
    Invalid,
}

fn handle_client(mut stream: TcpStream) {
    // read data into buffer.
    let mut buffer = Vec::new();
    match stream.read_to_end(&mut buffer) {
        Ok(n) => {
            if n == 0 {
                println!("connection closed!!!");
                return;
            }
            let req = match serde_json::from_slice::<Message::Request>(&buffer) {
                Ok(req) => {
                    println!("Received a valid request: {:?}", req);
                    req
                }
                Err(err) => {
                    let message = String::from_utf8_lossy(&buffer).to_string();
                    println!("Received an invalid message : {} ({})", message, err);
                    Message::Invalid
                }
            };
        }
        Err(err) => println!("error"),
    }
}

这就是我卡住的地方(作为使用rust 的初学者)。谁能帮我找到反/序列化请求/响应的标准方法。

最佳答案

这是完整的示例,您可以在其中以二进制格式而不是序列化库发送数据。

这是来自服务器的 main.rs 文件。

use std::io::{ErrorKind, Read, Write};
use std::net::TcpListener;
use std::sync::mpsc;
use std::thread;
use std::thread::sleep;
use std::time::Duration; 

const LOCAL: &str = "<type your server ip>:6000";
const MSG_SIZE: usize = 100;

fn main() {
    let server = TcpListener::bind(LOCAL).expect("Listener failed to bind");
    server.set_nonblocking(true).expect("failed to initialize non-blocking");

    let mut clients = vec![];
    let (tx, rx) = mpsc::channel::<String>();
    loop {

        if let Ok((mut socket, addr)) = server.accept() {
            println!("Client {} connected", addr);

            let tx = tx.clone();
            clients.push(socket.try_clone().expect("failed to clone client"));

            thread::spawn(move || loop {
                let mut buff = vec![0; MSG_SIZE];

                match socket.read_exact(&mut buff) {
                    Ok(_) => {
                        let msg = buff.into_iter().take_while(|&x| x != 0).collect::<Vec<_>>();
                        let msg = String::from_utf8(msg).expect("Invalid utf8 message");


                        println!("{}: {:?}", addr, msg);
                        tx.send(msg).expect("failed to send msg to rx");
                    }, 
                    Err(ref err) if err.kind() == ErrorKind::WouldBlock => (),
                    Err(_) => {
                        println!("closing connection with: {}", addr);
                        break;
                    }
                }

            });
        }

        if let Ok(msg) = rx.try_recv() {
            clients = clients.into_iter().filter_map(|mut client| {
                let mut buff = msg.clone().into_bytes();
                buff.resize(MSG_SIZE, 0);

                client.write_all(&buff).map(|_| client).ok()
            }).collect::<Vec<_>>();
        }

    }

}

在服务器项目中,您还可以在Cargo.toml 文件中添加依赖。

[dependencies]
time = "0.1.42"

最后,这是客户端项目的main.rs。

use std::io::{self, ErrorKind, Read, Write};
use std::net::TcpStream;
use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::time::Duration;


const LOCAL: &str = "<type your server ip>:6000";
const MSG_SIZE: usize = 100;
fn main() {
    let mut client = TcpStream::connect(LOCAL).expect("Stream failed to connect");
    client.set_nonblocking(true).expect("failed to initiate non-blocking");
    let (tx, rx) = mpsc::channel::<String>();
    thread::spawn(move || loop {
        let mut buff = vec![0; MSG_SIZE];
        match client.read_exact(&mut buff) {
            Ok(_) => {
                let msg = buff.into_iter().take_while(|&x| x != 0).collect::<Vec<_>>();
                println!("message recv {:?}", msg);
            },
            Err(ref err) if err.kind() == ErrorKind::WouldBlock => (),
            Err(_) => {
                println!("connection with server was severed");
                break;
            }
        }

        match rx.try_recv() {
            Ok(msg) => {
                let mut buff = msg.clone().into_bytes();
                buff.resize(MSG_SIZE, 0);
                client.write_all(&buff).expect("writing to socket failed");
            }, 
            Err(TryRecvError::Empty) => (),
            Err(TryRecvError::Disconnected) => break
        }

        thread::sleep(Duration::from_millis(100));
    });

    println!("Write a Message:");
    loop {
        let mut buff = String::new();
        io::stdin().read_line(&mut buff).expect("reading from stdin failed");
        let msg = buff.trim().to_string();
        if msg == ":quit" || tx.send(msg).is_err() {break}
    }
    println!("bye bye!");
}

关于rust - 使用 rust serde 反序列化请求和响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57586624/

相关文章:

parsing - 在 Rust 中反序列化键 = 值字符串列表的最佳方法

rust - 在方法中使用特征和泛型的 Rust 语法是什么?

rust - 如何仅允许 dead_code 和 unused_imports 用于开发构建?

rust - 不能借用 `self.hash` 作为可变的,因为它也被借用为不可变的

csv - 使用 Serde 将结构实例写入文件时如何向结构实例添加额外的数据点?

rust - 在 Rust 中,将带有可选参数的平面 JSON 反序列化为嵌套结构和枚举

rust - 反序列化具有通用类型的可选结构字段会导致语义怪异

hashmap - 恢复到 HashMap 中的先前值

正则表达式匹配两个相同的连续字符

json - 无法使用本地创建的向量,因为 "borrowed"