How to get data from TcpStream?

I'm new to Rust.

mod errors;
mod result;

#[cfg(test)]
mod tests;

use std::io::{Error, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;

pub use self::errors::ServerSessionError;
pub use self::result::ServerSessionResult;

pub struct Server {
    addr: Option<String>,
    listener: TcpListener,
}

impl Server {
    pub fn new() -> Result<(Server, Vec<ServerSessionResult>), ServerSessionError> {
        let server = Server {
            addr: Some("somewhere".to_string()),
            listener: TcpListener::bind("127.0.0.1:1935").unwrap(),
        };

        let mut results = Vec::with_capacity(4);

        Ok((server, results))
    }
    
    pub fn listen_and_serve(&self) {
        // Build a server
        println!("Listening...");
        for streams in self.listener.incoming() {
            match streams {
                Err(e) => { eprintln!("error: {}", e) },
                Ok(stream) => {
                    thread::spawn(move || {
                        handler(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
                    });
                }
            }
        }
    }
}

// Starts with being connected from a client
fn handler(mut stream: TcpStream) -> Result<(), Error> {
    println!("Connection from {}", stream.peer_addr()?);
    let mut buffer = [0; 1024];
    loop {
        let nbytes = stream.read(&mut buffer)?;
        if nbytes == 0 {
            return Ok(());
        }

        stream.write(&buffer[..nbytes])?;
        stream.flush()?;
    }
}

I could build a tcp server.
Then I want to print data from client.
Although I have googled TcpListener ,TcpStream, and BufReader, I don't know where to start.

Give me an advice...
Help me!

What are you trying to do?

That is my tcp server.
I tried to print data from a client, but my tryouts all threw errors...

Well what errors did it throw? I can't guess it from the code.

let host_and_port = format!("{}:{}", host, port);
let mut addrs = host_and_port.to_socket_addrs().unwrap();

if let Some(addr) = addrs.find(|x| (*x).is_ipv4()) {
  match TcpStream::connect(addr) {
    Err(_) => {
      println!("Connection NG.");
    }
    Ok(stream) => {
      println!("Connection Ok.");
      let mut reader = BufReader::new(&stream);
      let mut writer = BufWriter::new(&stream);
      // TODO
    }
  }
} else {
  eprintln!("Invalid Host:Port Number");
}
fn read_something (reader: &mut BufReader<&TcpStream>) {
  let mut msg = String::new();
  reader.read_line(&mut msg).expect("RECEIVE FAILURE!!!");
  // read_line は改行文字まで読む。
  // 他のread系のメソッドもある (https://doc.rust-lang.org/std/io/trait.BufRead.html)
  println!("{}", msg);
}

I saw those codes as a sample of tcp socket connection.

So I tried to make BufReader in my code.

mod errors;
mod result;

#[cfg(test)]
mod tests;

use std::io::{Error, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::io::BufReader;
use std::thread;

pub use self::errors::ServerSessionError;
pub use self::result::ServerSessionResult;

pub struct Server {
    addr: Option<String>,
    listener: TcpListener,
}

impl Server {
    pub fn new() -> Result<(Server, Vec<ServerSessionResult>), ServerSessionError> {
        let server = Server {
            addr: Some("somewhere".to_string()),
            listener: TcpListener::bind("127.0.0.1:1935").unwrap(),
        };

        let mut results = Vec::with_capacity(4);

        Ok((server, results))
    }
    
    pub fn listen_and_serve(&self) {
        // Build a server
        println!("Listening...");
        for streams in self.listener.incoming() {
            match streams {
                Err(e) => { eprintln!("error: {}", e) },
                Ok(stream) => {
                    thread::spawn(move || {
                        handler(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
                    });
                }
            }
        }
    }
}

// Starts with being connected from a client
fn handler(mut stream: TcpStream) -> Result<(), Error> {
    println!("Connection from {}", stream.peer_addr()?);
    let mut buffer = [0; 1024];

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

    loop {
        let nbytes = stream.read(&mut buffer)?;
        if nbytes == 0 {
            return Ok(());
        }

        let mut msg = String::new();
        reader.read_line(&mut msg).expect("Receive Failure");

        stream.write(&buffer[..nbytes])?;
        stream.flush()?;
    }
}

This is a code that I tried.
It throws this error:

   Compiling inferno-rtmp-engine v0.1.0 (/Users/kunosouichirou/Documents/GitHub/Inferno/inferno/inferno-rtmp-engine)
warning: trait objects without an explicit `dyn` are deprecated
  --> inferno-rtmp-engine/src/servers/errors.rs:24:32
   |
24 |     fn cause(&self) -> Option<&Fail> {
   |                                ^^^^ help: use `dyn`: `dyn Fail`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

error[E0599]: no method named `read_line` found for struct `std::io::BufReader<&std::net::TcpStream>` in the current scope
  --> inferno-rtmp-engine/src/servers/mod.rs:62:16
   |
62 |         reader.read_line(&mut msg).expect("Receive Failure");
   |                ^^^^^^^^^ method not found in `std::io::BufReader<&std::net::TcpStream>`
   |
   = help: items from traits can only be used if the trait is in scope
   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
           `use std::io::BufRead;`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: could not compile `inferno-rtmp-engine`.

To learn more, run the command again with --verbose.

I have tried other ways to use reader, but they did not work...

The thing is that read_line is not defined on BufReader. It's a method on the BufRead trait, which BufReader implements. This means that to use the method, you have to import the BufRead trait:

use std::io::BufRead;

This is similar to how you have imported the Read and Write traits.

1 Like

I'll try it and solve some errors!

I succeeded to print value!

mod errors;
mod result;

#[cfg(test)]
mod tests;

use std::io::{Error, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;

pub use self::errors::ServerSessionError;
pub use self::result::ServerSessionResult;

pub struct Server {
    addr: Option<String>,
    listener: TcpListener,
}

impl Server {
    pub fn new() -> Result<(Server, Vec<ServerSessionResult>), ServerSessionError> {
        let server = Server {
            addr: Some("somewhere".to_string()),
            listener: TcpListener::bind("127.0.0.1:1935").unwrap(),
        };

        let mut results = Vec::with_capacity(4);

        Ok((server, results))
    }

    pub fn listen_and_serve(&self) {
        // Build a server
        println!("Listening...");
        for streams in self.listener.incoming() {
            match streams {
                Err(e) => { eprintln!("error: {}", e) },
                Ok(stream) => {
                    thread::spawn(move || {
                        handler(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
                    });
                }
            }
        }
    }
}

fn handler(mut stream: TcpStream) -> Result<(), Error> {
    println!("Connection from {}", stream.peer_addr()?);
    let mut buffer = [0; 8192];
    loop {
        let nbytes = stream.read(&mut buffer)?;
        if nbytes == 0 {
            return Ok(());
        }

        for i in 0..nbytes {
            print!("{}", buffer[i]);
        }
        println!("");

        // Write buffer to socket
        stream.write(&buffer[..nbytes])?;
        stream.flush()?;
    }
}

thanks.

1 Like