mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-09-25 12:00:35 +00:00

This commit removes the `Handle` argument from the following constructors * `TcpListener::bind` * `TcpStream::connect` * `UdpSocket::bind` The `Handle` argument remains on the various `*_std` constructors as they're more low-level, but this otherwise is intended to set forth a precedent of by default not taking `Handle` arguments and instead relying on the global `Handle::default` return value when necesary.
80 lines
2.6 KiB
Rust
80 lines
2.6 KiB
Rust
//! This is a basic example of leveraging `UdpCodec` to create a simple UDP
|
|
//! client and server which speak a custom protocol.
|
|
//!
|
|
//! Here we're using the a custom codec to convert a UDP socket to a stream of
|
|
//! client messages. These messages are then processed and returned back as a
|
|
//! new message with a new destination. Overall, we then use this to construct a
|
|
//! "ping pong" pair where two sockets are sending messages back and forth.
|
|
|
|
extern crate tokio;
|
|
extern crate env_logger;
|
|
extern crate futures;
|
|
extern crate futures_cpupool;
|
|
|
|
use std::io;
|
|
use std::net::SocketAddr;
|
|
|
|
use futures::{Future, Stream, Sink};
|
|
use futures::future::Executor;
|
|
use futures_cpupool::CpuPool;
|
|
use tokio::net::{UdpSocket, UdpCodec};
|
|
|
|
pub struct LineCodec;
|
|
|
|
impl UdpCodec for LineCodec {
|
|
type In = (SocketAddr, Vec<u8>);
|
|
type Out = (SocketAddr, Vec<u8>);
|
|
|
|
fn decode(&mut self, addr: &SocketAddr, buf: &[u8]) -> io::Result<Self::In> {
|
|
Ok((*addr, buf.to_vec()))
|
|
}
|
|
|
|
fn encode(&mut self, (addr, buf): Self::Out, into: &mut Vec<u8>) -> SocketAddr {
|
|
into.extend(buf);
|
|
addr
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
drop(env_logger::init());
|
|
|
|
let pool = CpuPool::new(1);
|
|
|
|
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
|
|
|
|
// Bind both our sockets and then figure out what ports we got.
|
|
let a = UdpSocket::bind(&addr).unwrap();
|
|
let b = UdpSocket::bind(&addr).unwrap();
|
|
let b_addr = b.local_addr().unwrap();
|
|
|
|
// We're parsing each socket with the `LineCodec` defined above, and then we
|
|
// `split` each codec into the sink/stream halves.
|
|
let (a_sink, a_stream) = a.framed(LineCodec).split();
|
|
let (b_sink, b_stream) = b.framed(LineCodec).split();
|
|
|
|
// Start off by sending a ping from a to b, afterwards we just print out
|
|
// what they send us and continually send pings
|
|
// let pings = stream::iter((0..5).map(Ok));
|
|
let a = a_sink.send((b_addr, b"PING".to_vec())).and_then(|a_sink| {
|
|
let mut i = 0;
|
|
let a_stream = a_stream.take(4).map(move |(addr, msg)| {
|
|
i += 1;
|
|
println!("[a] recv: {}", String::from_utf8_lossy(&msg));
|
|
(addr, format!("PING {}", i).into_bytes())
|
|
});
|
|
a_sink.send_all(a_stream)
|
|
});
|
|
|
|
// The second client we have will receive the pings from `a` and then send
|
|
// back pongs.
|
|
let b_stream = b_stream.map(|(addr, msg)| {
|
|
println!("[b] recv: {}", String::from_utf8_lossy(&msg));
|
|
(addr, b"PONG".to_vec())
|
|
});
|
|
let b = b_sink.send_all(b_stream);
|
|
|
|
// Spawn the sender of pongs and then wait for our pinger to finish.
|
|
pool.execute(b.then(|_| Ok(()))).unwrap();
|
|
drop(a.wait());
|
|
}
|