diff options
author | Carl Lerche <me@carllerche.com> | 2019-10-22 10:13:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-22 10:13:49 -0700 |
commit | cfc15617a5247ea780c32c85b7134b88b6de5845 (patch) | |
tree | ef0a46c61c51505a60f386c9760acac9d1f9b7b1 /examples/proxy.rs | |
parent | b8cee1a60ad99ef28ec494ae4230e2ef4399fcf9 (diff) |
codec: move into tokio-util (#1675)
Related to #1318, Tokio APIs that are "less stable" are moved into a new
`tokio-util` crate. This crate will mirror `tokio` and provide
additional APIs that may require a greater rate of breaking changes.
As examples require `tokio-util`, they are moved into a separate
crate (`examples`). This has the added advantage of being able to avoid
example only dependencies in the `tokio` crate.
Diffstat (limited to 'examples/proxy.rs')
-rw-r--r-- | examples/proxy.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/examples/proxy.rs b/examples/proxy.rs new file mode 100644 index 00000000..6886a813 --- /dev/null +++ b/examples/proxy.rs @@ -0,0 +1,67 @@ +//! A proxy that forwards data to another server and forwards that server's +//! responses back to clients. +//! +//! Because the Tokio runtime uses a thread pool, each TCP connection is +//! processed concurrently with all other TCP connections across multiple +//! threads. +//! +//! You can showcase this by running this in one terminal: +//! +//! cargo run --example proxy +//! +//! This in another terminal +//! +//! cargo run --example echo +//! +//! And finally this in another terminal +//! +//! cargo run --example connect 127.0.0.1:8081 +//! +//! This final terminal will connect to our proxy, which will in turn connect to +//! the echo server, and you'll be able to see data flowing between them. + +#![warn(rust_2018_idioms)] + +use futures::{future::try_join, FutureExt, StreamExt}; +use std::{env, error::Error}; +use tokio::{ + io::AsyncReadExt, + net::{TcpListener, TcpStream}, +}; + +#[tokio::main] +async fn main() -> Result<(), Box<dyn Error>> { + let listen_addr = env::args().nth(1).unwrap_or("127.0.0.1:8081".to_string()); + let server_addr = env::args().nth(2).unwrap_or("127.0.0.1:8080".to_string()); + + println!("Listening on: {}", listen_addr); + println!("Proxying to: {}", server_addr); + + let mut incoming = TcpListener::bind(listen_addr).await?.incoming(); + + while let Some(Ok(inbound)) = incoming.next().await { + let transfer = transfer(inbound, server_addr.clone()).map(|r| { + if let Err(e) = r { + println!("Failed to transfer; error={}", e); + } + }); + + tokio::spawn(transfer); + } + + Ok(()) +} + +async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box<dyn Error>> { + let mut outbound = TcpStream::connect(proxy_addr).await?; + + let (mut ri, mut wi) = inbound.split(); + let (mut ro, mut wo) = outbound.split(); + + let client_to_server = ri.copy(&mut wo); + let server_to_client = ro.copy(&mut wi); + + try_join(client_to_server, server_to_client).await?; + + Ok(()) +} |