Tokio::net/mio::net and TCP Header

Hello.
I have simple TCP Server (Linux).

let done = listener.incoming().map_err(
   move |e| { /* log error */}).for_each(move |socket| {

   // socket.set...
    let processor = tcp_reader.for_each(
      move |bytes|{
           /* Process */ 
      }).and_then(move |()| {
          Ok(())
      }).or_else(move |err| {
          Err(err)
      }).then(move |result| {
          Ok(())
      });

      tokio::spawn(processor)
});  // Tokio 0.1.22
  1. How to get TCP Header from TcpStream?
  2. How to set IP_DONTFRAG flag etc. on socket?

You can't receive a raw tcp header from TcpStream, for that you'd need a raw socket. What exactly do you need from the header? Most of the information is retrievable...

On Unix/Linux you can use as_raw_fd, and then call setsockopt (requires unsafe).

AFAIK it doesn't make sense to set IP_DONTFRAG on a TCP socket, it's only for UDP/ICMP/raw IP...

Thanks for reply.
I need tcp header for debug.
I have strange problem with tcp - I am getting incomplete data in a packet, fragmented data (struct bytes) in Rust. But in the wireshark data is complete (same device).

Reading data from a socket won't provide all data for several reasons:

  • Receiving buffer wasn't large enough (If you've seen everything in wireshark, this is very likely the reason)
  • Kernel buffer wasn't large enough
  • The packet was fragmented somewhere on the way, etc...

In these kind of cases read_exact can help.

I can't really tell what the problem is without knowing what tcp_reader is (more details/code)...

Example, should read 4096 bytes or EOF, whatever comes first:

use tokio;
use tokio::prelude::*;
use tokio::net::TcpListener;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut listener = TcpListener::bind("127.0.0.1:1234").await?;
    
    while let Ok((mut client, _addr)) = listener.accept().await {
        let mut my_buffer = [0u8; 4096];
        let bytes_read = client.read_exact(&mut my_buffer).await?;
        println!("read {} bytes = {:?}", bytes_read, &my_buffer[..]);
    }
    
    Ok(())
}
1 Like

There is probably a bug in Tokio version 0.1.22.
I migrated to Tokio version 0.2.20 and it's OK.

Did you file a bug report on Tokio with a link to this thread?

1 Like

https://github.com/tokio-rs/tokio/issues/2492

That's not a bug. It's a misunderstanding of TCP. TCP offers a byte streaming, not packet transmission. There are no frame/packet/etc boundaries. Each intermediary (e.g. the Kernels send and receive buffers) are free to change frame boundaries as long as the overall data-stream stays intact.

If you need packet boundaries, you need to define an application protocol on top of TCP.

In Naim's example, this effect does not occur. The data is complete.
Where's the difference?
How to fix / set this example in Tokio 0.1.22?

In Naim's example, the read_exact method is used. It will ensure that the specified number of bytes is read by repeatedly calling read until the total number of returned bytes matches the requested length.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.