2017-11-06 19 views
3

クライアントからサーバーにJSON構造体を送信するために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は、無効な文字があるというエラーでそれを逆シリアル化しません。これを行うより良い方法はありますか?

+0

私はその存在を知らなかった。私はこの 'let input:Point3D = serde_json :: from_reader(&stream)?;'を試してみたところ、クライアントからのEOFを待つように見えます。クライアントからの特殊文字に対して 'from_reader'をどのようにして終了させるのですか? –

+0

それはEOF、ファイルからの読み込みの場合の特殊文字を見たとき、私は 'ファイルのリーダーの終了にfrom_reader'を考えhttps://docs.serde.rs/serde_json/fn.from_reader.htmlここでは例を見てみます。私は改行を特殊文字として扱い、改行を得る際に 'from_reader'が復帰する必要があるかどうか疑問に思っていました。または私はこれを誤解していますか? –

+0

EOFは「文字」ではありません。あなたは決して質問に答えることはできません:*あなたはプログラマーで、ソケットが "完了"したときを知っていますか?*あなたはプロトコルを定義していますが、実際にあなたのプロトコル*それを実装する方法を教えてくれません。改行は、ネットワークを介して来るデータと関係がありますか? – Shepmaster

答えて

2

置きBufReaderTcpStream。これにより、特定のバイト(この場合は改行)まで読むことができます。その後、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の配分を、再利用することで少し凝っているんです。私はまた、結果のメモリを割り当てることを避け、出力ストリームに直接印刷するだけです。

関連する問題