I am trying to implement a TCP client in Rust. I am able to read data coming from the server but I can not manage to send data.
Here is the code that I am working on:
extern crate bytes;
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
use self::bytes::BytesMut;
use self::futures::{Future, Poll, Stream};
use self::tokio_core::net::TcpStream;
use self::tokio_core::reactor::Core;
use self::tokio_io::AsyncRead;
use std::io;
#[derive(Default)]
pub struct TcpClient {}
struct AsWeGetIt<R>(R);
impl<R> Stream for AsWeGetIt<R>
where
R: AsyncRead,
{
type Item = BytesMut;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let mut buf = BytesMut::with_capacity(1000);
self.0
.read_buf(&mut buf)
.map(|async| async.map(|_| Some(buf)))
}
}
impl TcpClient {
pub fn new() -> Self {
Self {}
}
pub fn connectToTcpServer(&mut self) -> bool {
let mut core = Core::new().unwrap();
let handle = core.handle();
let address = "127.0.0.1:2323".parse().expect("Unable to parse address");
let connection = TcpStream::connect(&address, &handle);
let client = connection
.and_then(|tcp_stream| {
AsWeGetIt(tcp_stream).for_each(|buf| {
println!("{:?}", buf);
Ok(())
})
})
.map_err(|e| eprintln!("Error: {}", e));
core.run(client).expect("Unable to run the event loop");
return true;
}
}
How can I add asynchronous data sending functionality?
If you want to have two completely independent streams of data on the socket, you can use the split() method on the TcpStream in the current version of Tokio:
let connection = TcpStream::connect(&address);
connection.and_then(|socket| {
let (rx, tx) = socket.split();
//Independently use tx/rx for sending/receiving
return Ok(());
});
After the split, you can use rx (the receiving half) and tx (the sending half) independently. Here is a small example that treats sending and receiving as completely independent. The sender-half simply periodically sends the same message, whereas the receiving half just prints all incomming data:
extern crate futures;
extern crate tokio;
use self::futures::{Future, Poll, Stream};
use self::tokio::net::TcpStream;
use tokio::io::{AsyncRead, AsyncWrite, Error, ReadHalf};
use tokio::prelude::*;
use tokio::timer::Interval;
//Receiver struct that implements the future trait
//this exclusively handles incomming data and prints it to stdout
struct Receiver {
rx: ReadHalf<TcpStream>, //receiving half of the socket stream
}
impl Future for Receiver {
type Item = ();
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut buffer = vec![0u8; 1000]; //reserve 1000 bytes in the receive buffer
//get all data that is available to us at the moment...
while let Async::Ready(num_bytes_read) = self.rx.poll_read(&mut buffer)? {
if num_bytes_read == 0 {
return Ok(Async::Ready(()));
} //socket closed
print!("{}", String::from_utf8_lossy(&buffer[..num_bytes_read]));
}
return Ok(Async::NotReady);
}
}
fn main() {
let address = "127.0.0.1:2323".parse().expect("Unable to parse address");
let connection = TcpStream::connect(&address);
//wait for the connection to be established
let client = connection
.and_then(|socket| {
//split the successfully connected socket in half (receive / send)
let (rx, mut tx) = socket.split();
//set up a simple sender, that periodically (1sec) sends the same message
let sender = Interval::new_interval(std::time::Duration::from_millis(1000))
.for_each(move |_| {
//this lambda is invoked once per passed second
tx.poll_write(&vec![82, 117, 115, 116, 10]).map_err(|_| {
//shut down the timer if an error occured (e.g. socket was closed)
tokio::timer::Error::shutdown()
})?;
return Ok(());
}).map_err(|e| println!("{}", e));
//start the sender
tokio::spawn(sender);
//start the receiver
let receiver = Receiver { rx };
tokio::spawn(receiver.map_err(|e| println!("{}", e)));
return Ok(());
}).map_err(|e| println!("{}", e));
tokio::run(client);
}
For some applications, this is enough. However, often you will have a defined protocol / format on the connection. HTTP connections, for example, always consist of requests and responses, each of which consists of a header and the body. Instead of directly working on the byte level, Tokio offers the traits Encoder and Decoder you fit onto a socket, which decodes your protocol and directly gives you the entities you want to work with. For an example you can either look at the very basic HTTP implementation or the line-based codec.
It gets a bit more complicated when an incoming message triggers an outgoing message. For the simplest case (every incoming message leads to exactly one outgoing message) you can have a look at this official request / response example.
Related
I am finding it difficult to understand why and when I need to explicitly do something with the Context and/or its Waker passed to the poll method on an object for which I am implementing Future. I have been reading the documentation from Tokio and the Async Book, but I feel the examples/methods are too abstract to be applied to real problems.
For example, I would have thought the following MRE would deadlock since the future generated by new_inner_task would not know when a message has been passed on the MPSC channel, however, this example seems to work fine. Why is this the case?
use std::{future::Future, pin::Pin, task::{Context, Poll}, time::Duration};
use futures::{FutureExt, StreamExt}; // 0.3
use tokio::sync::mpsc; // 1.2
use tokio_stream::wrappers::UnboundedReceiverStream; // 0.1
async fn new_inner_task(rx: mpsc::UnboundedReceiver<()>) {
let mut requests = UnboundedReceiverStream::new(rx);
while let Some(_) = requests.next().await {
eprintln!("received request");
}
}
pub struct ActiveObject(Pin<Box<dyn Future<Output = ()> + Send>>);
impl ActiveObject {
pub fn new() -> (Self, mpsc::UnboundedSender<()>) {
let (tx, rx) = mpsc::unbounded_channel();
(Self(new_inner_task(rx).boxed()), tx)
}
}
impl Future for ActiveObject {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
eprintln!("[polled]");
self.get_mut().0.as_mut().poll(cx)
}
}
async fn delayed_send(delay: u64, sender: mpsc::UnboundedSender<()>) {
tokio::time::sleep(Duration::from_millis(delay)).await;
sender.send(()).unwrap();
eprintln!("sent request");
}
#[tokio::main]
async fn main() {
let (obj, tx) = ActiveObject::new();
let ds = delayed_send(500, tx.clone());
let ds2 = delayed_send(1000, tx);
tokio::join!(obj, ds, ds2);
}
The output that I get from running this example locally is:
[polled]
[polled]
sent request
[polled]
received request
[polled]
sent request
[polled]
received request
So, although I haven't done anything with Context or Waker, ActiveObject appears to get polled at a reasonable rate, that is, more frequently than required, but not busy-waiting. What is causing ActiveObject to be woken up/polled at this rate?
You are passing the same Context (and thus Waker) to the poll() method of the Future returned by new_inner_task, which passes it down the chain to the poll() of the Future returned by UnboundedReceiverStream::next(). The implementation of that arranges to call wake() on this Waker at the appropriate time (when new elements appear in the channel). When that is done, Tokio polls the top-level future associated with this Waker - the join!() of the three futures.
If you omitted the line that polls the inner task and just returned Poll::Pending instead, you would get the expected situation, where your Future would be polled once and then "hang" forever, as nothing would wake it again.
I am working a project to peek the connection and get the raw byte data of the client hello from a client attempting to connect to a rust tcp server. However, I'm a little lost as to how to approach this, especially being a beginner of rust.
So far, this is what I have, but it seems like I am misunderstanding what data is sent by the tcpstream. How can I access the client hello data?
let listener = TcpListener::bind("127.0.0.1:8000").unwrap();
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let mut buf: Vec<u8> = vec![0; 1024];
let len = stream.peek(&mut buf).expect("peek failed");
}
Err(e) => { /* connection failed */ }
}
}
I am working on a simple Lambda function and I was wondering if I could pass in client (dynamodb this time) to the handler, so we do not re-connect for every request.
The macro is defined here:
https://docs.rs/lambda_http/0.1.1/lambda_http/macro.lambda.html 3
My function so far:
fn main() -> Result<(), Box<dyn Error>> {
simple_logger::init_with_level(log::Level::Debug)?;
info!("Starting up...");
let dynamodb_client = DynamoDbClient::new(Region::EuCentral1);
lambda!(router);
return Ok(());
}
fn router(req: Request, ctx: Context) -> Result<impl IntoResponse, HandlerError> {
let h_req = HReq {
http_path: req.uri().path(),
http_method: req.method(),
};
match h_req {
HReq {
http_path: "/login",
http_method: &Method::POST,
} => user_login(req, ctx),
_ => {
error!(
"Not supported http method or path {}, {}",
h_req.http_path, h_req.http_method
);
let mut resp = Response::default();
*resp.status_mut() = StatusCode::METHOD_NOT_ALLOWED;
Ok(resp)
}
}
}
Is it possible to extend this macro to have a second option so I can add the client all the way down to the functions which are actually talking to the database?
DynamoDB is a web service, each request to it is treated as a distinct API call.
There is no functionality to keep a client connection alive in the same way you would with a regular database connection (e.g. MySQL).
My rust knowledge is a little lacking, so I don't know if http keepalive is set by default with the DynamoDBClient, but making sure http keepalive is set will help performance.
After considering all the options I decided to implement this with lazy_static.
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref DYNAMODB_CLIENT: DynamoDbClient = DynamoDbClient::new(Region::EuCentral1);
}
This is getting instantiated at run time and can be used internally in the module without any problems.
I would like to create a future that completes if a certain value is received over a UDP connection.
To clarify, assume I send a ping with id 2 and want to asynchronously wait for the pong with the same id. My idea was to use something like send_ping(endpoint, id) -> Future and work with the future (e.g. passing it to other functions) knowing that it either resolves to the matching pong or to a timeout.
A sketch of my idea:
extern crate tokio_core;
extern crate futures;
use tokio_core::reactor::*;
use futures::Stream;
use futures::sync::mpsc;
fn main() {
let mut core = Core::new().unwrap();
// simulate my UDP socket connection
let (remote, socket) = mpsc::unbounded::<i32>();
remote.unbounded_send(1).unwrap();
remote.unbounded_send(2).unwrap();
remote.unbounded_send(3).unwrap();
let reader = socket.for_each(|id| {
println!("received {}", id);
Ok(())
});
// create future which completes if 2 is received
// or after a given timeout
core.run(reader).unwrap();
}
Is this even possible? I cannot find any examples.
You can use tokio_timer::Timer::timeout_stream and futures::Stream::filter:
extern crate futures;
extern crate tokio_core;
extern crate tokio_timer;
use tokio_core::reactor::*;
use futures::Stream;
use futures::sync::mpsc;
use std::time::Duration;
fn main() {
let mut core = Core::new().unwrap();
let timer = tokio_timer::Timer::default();
// simulate my UDP socket connection
let (remote, socket) = mpsc::unbounded::<i32>();
remote.unbounded_send(1).unwrap();
remote.unbounded_send(2).unwrap();
remote.unbounded_send(3).unwrap();
let consumer = timer
.timeout_stream(socket, Duration::from_secs(2))
.filter(|&v| v == 2)
.for_each(|id| {
println!("received {}", id);
Ok(())
});
println!("{:?}", core.run(consumer));
}
I want to do message broadcasting: when one of the clients sends a message, the server writes it to each socket. My main problem is I can't figure out how to send the Vec to the threads. I can't use Mutex because that will lock the access of other threads to the Vec for reading. I can't clone and send because TcpStream can't be cloned and sent. Here's my attempt until now
use std::net::{TcpStream, TcpListener};
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc::{channel, Receiver};
use std::cell::RefCell;
type StreamSet = Arc<RefCell<Vec<TcpStream>>>;
type StreamReceiver = Arc<Mutex<Receiver<StreamSet>>>;
fn main() {
let listener = TcpListener::bind("0.0.0.0:8000").unwrap();
let mut connection_set: StreamSet = Arc::new(RefCell::new(vec![]));
let mut id = 0;
let (tx, rx) = channel();
let rx = Arc::new(Mutex::new(rx));
for stream in listener.incoming() {
let receiver = rx.clone();
let stream = stream.unwrap();
(*connection_set).borrow_mut().push(stream);
println!("A connection established with client {}", id);
thread::spawn(move || handle_connection(receiver, id));
id += 1;
tx.send(connection_set.clone()).unwrap();
}
}
fn handle_connection(rx: StreamReceiver, id: usize) {
let streams;
{
streams = *(rx.lock().unwrap().recv().unwrap()).borrow();
}
let mut connection = &streams[id];
loop {
let mut buffer = [0; 512];
if let Err(_) = connection.read(&mut buffer) {
break;
};
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
if let Err(_) = connection.write(&buffer[..]) {
break;
};
if let Err(_) = connection.flush() {
break;
};
}
}
Another idea is to spawn a single "controller" thread and a thread for every socket. Each thread would own the socket and have a channel to send data back to the controller. The controller would own a Vec of channels to send to each thread. When a thread receives data, you send it to the controller which duplicates it and sends it back to each worker thread. You can wrap the data in an Arc to prevent unneeded duplication, and you should provide an ID to avoid echoing the data back to the original sender (if you need to).
This moves the ownership completely within a single thread, which should avoid the issues you are experiencing.
You may also wish to look into Tokio, which should allow you to do something similar but without the need to spawn threads in a 1-1 mapping.
I can't use Mutex because that will lock the access of other threads
You can always try a different locking mechanism such as a RwLock.
because TcpStream can't be cloned
Sure it can: TcpStream::try_clone.