Search code examples
rustrust-tokio

How to write using tokio Framed LinesCodec?


The following code reads from my server successfully, however I cannot seem to get the correct syntax or semantics to write back to the server when a particular line command is recognized. Do I need to create a FramedWriter? Most examples I have found split the socket but that seems overkill I expect the codec to be able to handle the bi-directional io by providing some async write method.

# Cargo.toml
[dependencies]
tokio = { version = "0.3", features = ["full"] }
tokio-util = { version = "0.4", features = ["codec"] }
//! main.rs
use tokio::net::{ TcpStream };
use tokio_util::codec::{ Framed, LinesCodec };
use tokio::stream::StreamExt;
use std::error::Error;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let saddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081); 
    let conn = TcpStream::connect(saddr).await?;

    let mut server = Framed::new(conn, LinesCodec::new_with_max_length(1024));

    while let Some(Ok(line)) = server.next().await {
        match line.as_str() {
            "READY" => println!("Want to write a line to the stream"),
            _ => println!("{}", line),
        }
    }

    Ok({})
}

Solution

  • According to the documentation, Framed implements Stream and Sink traits. Sink defines only the bare minimum of low-level sending methods. To get the high-level awaitable methods like send() and send_all(), you need to use the SinkExt extension trait.

    For example (playground):

    use futures::sink::SinkExt;
    // ...
    
    while let Some(Ok(line)) = server.next().await {
        match line.as_str() {
            "READY" => server.send("foo").await?,
            _ => println!("{}", line),
        }
    }