summaryrefslogtreecommitdiffstats
path: root/examples/proxy.rs
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2019-10-22 10:13:49 -0700
committerGitHub <noreply@github.com>2019-10-22 10:13:49 -0700
commitcfc15617a5247ea780c32c85b7134b88b6de5845 (patch)
treeef0a46c61c51505a60f386c9760acac9d1f9b7b1 /examples/proxy.rs
parentb8cee1a60ad99ef28ec494ae4230e2ef4399fcf9 (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.rs67
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(())
+}