0
votes

I am trying to de/serialize request and response on server/client side. Below is my what I have tried :-

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"),
    }
}

This is where I am stuck (being a beginner in rust). Can anyone please help me with finding standard way for de/serializing request/response.

1
and what is the problem? You can put you code on play.rust-lang.org to show minimal error example - S.R
Here is a runnable reproduction of the problem - please try to include these yourself in future, as it makes it much easier to solve the problem! - Joe Clay

1 Answers

-1
votes

Here is the complete example in which you can send the data in binary format rather than the serialized library.

This is the main.rs file from the server.

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<_>>();
        }

    }

}

In the server project, you can also add the dependencies in Cargo.toml file.

[dependencies]
time = "0.1.42"

In last, this is the main.rs of the client project.

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!");
}