009 Rust 網路程式設計,序列化與反序列化

linghuyichong發表於2020-05-03

介紹

serde crate 是 Serde 生態的核心。serde_derive crate 提供必要的工具,使用過程宏來派生 Serialize 和 Deserialize。但是serde只提供序列化和反序列化的框架,具體的操作還需要依賴具體的包,如serde_json和serde_yaml等。
下面透過兩個例子來介紹。

序列化與序列化示例

簡單例項一

  • 建立工程

    cargo new use_ser
  • 修改Cargo.toml檔案,新增依賴

    [dependencies]
    serde = { version = "1.0.106", features = ["derive"] }
    serde_json = "1.0.52"
    serde_yaml = "0.8.11"
  • 編寫原始碼:

    use serde::{Serialize, Deserialize};
    #[derive(Serialize, Deserialize, Debug)]
    struct ServerConfig {
      workers: u64,
      ignore: bool,
      auth_server: Option<String>,
    }
    fn main() {
      let config = ServerConfig {
          workers: 100,
          ignore: false,
          auth_server: Some(String::from("auth.server.io")),
      };
      {
          println!("To and from Json");
          let serialized = serde_json::to_string(&config).unwrap();
          println!("serialized: {}", serialized);
          println!("");
    
          let deserialized: ServerConfig = serde_json::from_str(&serialized).unwrap();
          println!("deserialized: {:#?}", deserialized);
      }
    
      println!("");
      println!("");
    
      {
          println!("To and from Yaml");
          let serialized = serde_yaml::to_string(&config).unwrap();
          println!("serialized: {}", serialized);
    
          println!("");
          let deserialized: ServerConfig = serde_yaml::from_str(&serialized).unwrap();
          println!("deserialized: {:#?}", deserialized);
      }
    }
  • 執行結果

    To and from Json
    serialized: {"workers":100,"ignore":false,"auth_server":"auth.server.io"}
    deserialized: ServerConfig {
      workers: 100,
      ignore: false,
      auth_server: Some(
          "auth.server.io",
      ),
    }
    To and from Yaml
    serialized: ---
    workers: 100
    ignore: false
    auth_server: auth.server.io
    deserialized: ServerConfig {
      workers: 100,
      ignore: false,
      auth_server: Some(
          "auth.server.io",
      ),
    }

    網路例子

    server端

  • 建立工程

    cargo new server
  • 修改Cargo.toml檔案,新增依賴

    [dependencies]
    serde = { version = "1.0.106", features = ["derive"] }
    serde_json = "1.0.52"
  • 原始碼

    use serde::{Deserialize, Serialize};
    use serde_json;
    use std::io::{self, prelude::*, BufReader, Write};
    use std::net::{TcpListener, TcpStream};
    use std::{str, thread};
    #[derive(Debug, Serialize, Deserialize)]
    struct Point3D {
      x: u32,
      y: u32,
      z: u32,
    }
    fn handle_client(stream: TcpStream) -> io::Result<()> {
      println!("Incoming connection from: {}", stream.peer_addr()?);
      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);
    
          stream.get_mut().write(&(serde_json::to_vec(&(f64::from(value).sqrt()))?))?;
          stream.get_mut().write(&("\n".as_bytes()))?;
          stream.get_mut().flush()?;
    
          // write!(stream.get_mut(), "{}", f64::from(value).sqrt())?;
          // write!(stream.get_mut(), "{}", "\n")?;
      }
    }
    fn main() -> io::Result<()> {
      let listener = TcpListener::bind("0.0.0.0:8080")?;
      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));
                  });
              }
          }
      }
    
      Ok(())
    }

    client端

  • 建立工程

    cargo new client
  • 修改Cargo.toml檔案,新增依賴

    [dependencies]
    serde = { version = "1.0.106", features = ["derive"] }
    serde_json = "1.0.52"
  • 原始碼

    use serde::{Deserialize, Serialize};
    use serde_json;
    use std::io::{self, prelude::*, BufReader, Write};
    use std::net::TcpStream;
    use std::str;
    #[derive(Debug, Serialize, Deserialize)]
    struct Point3D {
      x: u32,
      y: u32,
      z: u32,
    }
    fn main() -> io::Result<()> {
      let mut stream = TcpStream::connect("127.0.0.1:8080")?;
    
      println!("Please provide a 3D point as three comma separated integers");
      loop {
          let mut input = String::new();
          let mut buffer: Vec<u8> = Vec::new();
          io::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_all(serde_json::to_string(&point).unwrap().as_bytes())
              .expect("Failed to write to server");
          stream.write_all(b"\n").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");
          let input = str::from_utf8(&buffer).expect("Could not write buffer as string");
          if input == "" {
              eprintln!("Empty response from server");
          }
          print!("Response from server {}", input);
      }
    }

    執行方式

  • 先起server端

    cargo run server
  • 起客戶端

    cargo run client

    客戶端如下:

    Please provide a 3D point as three comma separated integers
    1,2,3 //輸入1,2,3
    Response from server 3.7416573867739413 //返回計算結果
本作品採用《CC 協議》,轉載必須註明作者和本文連結
令狐一衝

相關文章