From 18e35d0434558013cb047d1061a44d0bc2b8d178 Mon Sep 17 00:00:00 2001 From: Andy Gauge Date: Fri, 19 May 2017 10:30:50 -0700 Subject: [PATCH 1/5] Added networking example to listen on random socket using tcp/ip --- src/intro.md | 2 ++ src/net.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/intro.md b/src/intro.md index 6b3d6764..8a0fd085 100644 --- a/src/intro.md +++ b/src/intro.md @@ -58,6 +58,7 @@ community. It needs and welcomes help. For details see | [Query the GitHub API][ex-rest-get] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | | [Check if an API Resource Exists][ex-rest-head] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] | | [Create and delete Gist with GitHub API][ex-rest-post] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | +| [Listen on Unused port TCP/IP][ex-random-port-tcp] | [![std-badge]][std] | [![cat-net-badge]][cat-net] | ## [Application development](app.html) @@ -167,6 +168,7 @@ Keep lines sorted. [ex-rand-custom]: basics.html#ex-rand-custom [ex-rand-dist]: basics.html#ex-rand-dist [ex-rand-float]: basics.html#ex-rand-float +[ex-random-port-tcp]: net.html#ex-random-port-tcp [ex-rand-range]: basics.html#ex-rand-range [ex-rayon-iter-mut]: concurrency.html#ex-rayon-iter-mut [ex-rest-head]: net.html#ex-rest-head diff --git a/src/net.md b/src/net.md index 53bfb911..e73411d3 100644 --- a/src/net.md +++ b/src/net.md @@ -12,6 +12,7 @@ | [Query the GitHub API][ex-rest-get] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | | [Check if an API Resource Exists][ex-rest-head] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] | | [Create and delete Gist with GitHub API][ex-rest-post] | [![reqwest-badge]][reqwest] [![serde-badge]][serde] | [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] | +| [Listen on Unused port TCP/IP][ex-random-port-tcp] | [![std-badge]][std] | [![cat-net-badge]][cat-net] | [ex-url-parse]: #ex-url-parse @@ -537,6 +538,73 @@ fn run() -> Result<()> { quick_main!(run); ``` +[ex-random-port-tcp]: #ex-random-port-tcp + +## Listen on Unused port TCP/IP + +[![std-badge]][std] [![cat-net-badge]][cat-net] + +Give the OS the responsibility to pick an unused [registered port]. These ports +generally do not require sudo permission to bind to, and can be helpful when +establishing connections with clients in a disposable communication chain. +These ports begin with 1024 and have around 48,000 available. Typically, a +known port is used to initiate the communication and subsequent communication +occurs on the registered port after a handshake process. + +In this example, the port is displayed on the console, and will listen until a +request is made. If you use your browser to test this program, simply enter +the address:port into your location bar and make the request. Because the +program returns nothing, the browser's stop feature can be used to speed things +up. + +```rust, no_run +#[macro_use] +extern crate error_chain; + +use std::net::{SocketAddrV4, Ipv4Addr,TcpListener}; +use std::io::Read; + +error_chain! { + foreign_links { + Io(::std::io::Error); + } +} + +fn run() -> Result<()>{ + let loopback = Ipv4Addr::new(127,0,0,1); + // Assigning port 0 requests the OS to assign a free port + let socket = SocketAddrV4::new(loopback, 0); + let listen = TcpListener::bind(socket)?; + let port = listen.local_addr()?; + println!("Listening on {}, access this port to end the program", port); + match listen.accept() { + Ok((mut tcp_stream, addr)) => { + // read from the socket until connection closed by client. + let mut input = String::new(); + let _ = tcp_stream.read_to_string(&mut input); //discard byte count + println!("Connection received! \r\n{:?} says {}", addr, input); + Ok(()) + }, + Err(e) => { Err(e.into()) } + } +} + +quick_main!(run); +``` + +The `std` library is leveraged to make a well formed IP/port with the +`SocketAddrV4` and `Ipv4Addr` structs. The loopback address is a special +address that runs only on the local machine, and is available on all machines. + +By passing 0 to the [`TcpListener::bind`], the OS will assign an unused random +port. The address and port that the OS assigns is available using +[`TcpListener::local_addr`]. + +The rest of the recipe prints out the request made on the socket. +`TcpListener::accept` returns a tuple of `TcpStream` and client information +within a `Result`. The `Read` implmentation is used on that `TcpStream` to +collect the request payload. Closing the program is as easy as browsing to the +ip:port or using telnet to send some data, pressing ctrl-] and typing quit. [cat-encoding-badge]: https://img.shields.io/badge/-encoding-red.svg @@ -552,6 +620,8 @@ quick_main!(run); [reqwest]: https://docs.rs/reqwest/ [serde-badge]: https://img.shields.io/crates/v/serde.svg?label=serde [serde]: https://docs.rs/serde/ +[std]: https://doc.rust-lang.org/std +[std-badge]: https://img.shields.io/badge/std-1.17.0-blue.svg [tempdir-badge]: https://img.shields.io/crates/v/tempdir.svg?label=tempdir [tempdir]: https://docs.rs/tempdir/ [url-badge]: https://img.shields.io/crates/v/url.svg?label=url @@ -582,3 +652,6 @@ quick_main!(run); [`serde_json::json!`]: https://docs.rs/serde_json/*/serde_json/macro.json.html [`TempDir::new`]: https://docs.rs/tempdir/*/tempdir/struct.TempDir.html#method.new [`TempDir::path`]: https://docs.rs/tempdir/*/tempdir/struct.TempDir.html#method.path +[registered port]: https://en.wikipedia.org/wiki/Registered_port +[`TcpListener::bind`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html#method.bind +[`TcpListener::local_addr`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html#method.local_addr From e5c7db1d10c059af4a9f5e2e648c9f3cd214f45d Mon Sep 17 00:00:00 2001 From: Andy Gauge Date: Fri, 19 May 2017 11:45:31 -0700 Subject: [PATCH 2/5] fixed spaces, added telnet example, and properly returned errors --- src/net.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/net.md b/src/net.md index e73411d3..431c8495 100644 --- a/src/net.md +++ b/src/net.md @@ -561,7 +561,7 @@ up. #[macro_use] extern crate error_chain; -use std::net::{SocketAddrV4, Ipv4Addr,TcpListener}; +use std::net::{SocketAddrV4, Ipv4Addr, TcpListener}; use std::io::Read; error_chain! { @@ -570,23 +570,19 @@ error_chain! { } } -fn run() -> Result<()>{ - let loopback = Ipv4Addr::new(127,0,0,1); +fn run() -> Result<()> { + let loopback = Ipv4Addr::new(127, 0, 0, 1); // Assigning port 0 requests the OS to assign a free port let socket = SocketAddrV4::new(loopback, 0); let listen = TcpListener::bind(socket)?; let port = listen.local_addr()?; println!("Listening on {}, access this port to end the program", port); - match listen.accept() { - Ok((mut tcp_stream, addr)) => { - // read from the socket until connection closed by client. - let mut input = String::new(); - let _ = tcp_stream.read_to_string(&mut input); //discard byte count - println!("Connection received! \r\n{:?} says {}", addr, input); - Ok(()) - }, - Err(e) => { Err(e.into()) } - } + let (mut tcp_stream, addr) = listen.accept()?; //block until requested + let mut input = String::new(); + // read from the socket until connection closed by client. + let _ = tcp_stream.read_to_string(&mut input)?; //discard byte count + println!("Connection received! \r\n{:?} says {}", addr, input); + Ok(()) } quick_main!(run); @@ -604,7 +600,9 @@ The rest of the recipe prints out the request made on the socket. `TcpListener::accept` returns a tuple of `TcpStream` and client information within a `Result`. The `Read` implmentation is used on that `TcpStream` to collect the request payload. Closing the program is as easy as browsing to the -ip:port or using telnet to send some data, pressing ctrl-] and typing quit. +ip:port or using `telnet ip port` to send some data. For example, if the +program shows Listening on 127.0.0.1:11500, run `telnet 127.0.0.1 11500`. After +sending data in telnet press `ctrl-]` and type `quit`. [cat-encoding-badge]: https://img.shields.io/badge/-encoding-red.svg From 25b53f79918bdb657f263483d4cc6b7357294dcb Mon Sep 17 00:00:00 2001 From: Andy Gauge Date: Fri, 19 May 2017 14:07:19 -0700 Subject: [PATCH 3/5] Reword description and comments, variable names to match tense. --- src/net.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/net.md b/src/net.md index 431c8495..a3c5d0f6 100644 --- a/src/net.md +++ b/src/net.md @@ -574,14 +574,15 @@ fn run() -> Result<()> { let loopback = Ipv4Addr::new(127, 0, 0, 1); // Assigning port 0 requests the OS to assign a free port let socket = SocketAddrV4::new(loopback, 0); - let listen = TcpListener::bind(socket)?; - let port = listen.local_addr()?; + let listener = TcpListener::bind(socket)?; + let port = listener.local_addr()?; println!("Listening on {}, access this port to end the program", port); - let (mut tcp_stream, addr) = listen.accept()?; //block until requested + let (mut tcp_stream, addr) = listener.accept()?; //block until requested + println!("Connection received! {:?} is sending data.", addr); let mut input = String::new(); - // read from the socket until connection closed by client. - let _ = tcp_stream.read_to_string(&mut input)?; //discard byte count - println!("Connection received! \r\n{:?} says {}", addr, input); + // read from the socket until connection closed by client, discard byte count. + let _ = tcp_stream.read_to_string(&mut input)?; + println!("{:?} says {}", addr, input); Ok(()) } @@ -589,7 +590,7 @@ quick_main!(run); ``` The `std` library is leveraged to make a well formed IP/port with the -`SocketAddrV4` and `Ipv4Addr` structs. The loopback address is a special +[`SocketAddrV4`] and [`Ipv4Addr`] structs. The loopback address is a special address that runs only on the local machine, and is available on all machines. By passing 0 to the [`TcpListener::bind`], the OS will assign an unused random @@ -597,12 +598,15 @@ port. The address and port that the OS assigns is available using [`TcpListener::local_addr`]. The rest of the recipe prints out the request made on the socket. -`TcpListener::accept` returns a tuple of `TcpStream` and client information -within a `Result`. The `Read` implmentation is used on that `TcpStream` to -collect the request payload. Closing the program is as easy as browsing to the -ip:port or using `telnet ip port` to send some data. For example, if the -program shows Listening on 127.0.0.1:11500, run `telnet 127.0.0.1 11500`. After -sending data in telnet press `ctrl-]` and type `quit`. +[`TcpListener::accept`] returns a `(`[`TcpStream`], [`SocketAddrV4`]`)` +representing the data from the client, its IP address and port. Reading on the +socket with [`read_to_string`] will wait until the connection is closed which +can be tested with `telnet ip port`. For example, if the program shows +Listening on 127.0.0.1:11500, run + +`telnet 127.0.0.1 11500` + +After sending data in telnet press `ctrl-]` and type `quit`. [cat-encoding-badge]: https://img.shields.io/badge/-encoding-red.svg @@ -645,11 +649,15 @@ sending data in telnet press `ctrl-]` and type `quit`. [`RequestBuilder::json`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.json [`RequestBuilder::send`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.send [`read_to_string`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_string +[registered port]: https://en.wikipedia.org/wiki/Registered_port [`String`]: https://doc.rust-lang.org/std/string/struct.String.html [`serde::Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html [`serde_json::json!`]: https://docs.rs/serde_json/*/serde_json/macro.json.html [`TempDir::new`]: https://docs.rs/tempdir/*/tempdir/struct.TempDir.html#method.new [`TempDir::path`]: https://docs.rs/tempdir/*/tempdir/struct.TempDir.html#method.path -[registered port]: https://en.wikipedia.org/wiki/Registered_port +[`Ipv4Addr`]: https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html +[`SocketAddrV4`]: https://doc.rust-lang.org/std/net/struct.SocketAddrV4.html +[`TcpListener::accept`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html#method.accept [`TcpListener::bind`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html#method.bind [`TcpListener::local_addr`]: https://doc.rust-lang.org/std/net/struct.TcpListener.html#method.local_addr +[`TcpStream`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html From eaf2abc6bf90681de99e2a07865f31880b119ad1 Mon Sep 17 00:00:00 2001 From: Andy Gauge Date: Fri, 19 May 2017 15:29:03 -0700 Subject: [PATCH 4/5] Make language more concise / readable --- src/net.md | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/net.md b/src/net.md index a3c5d0f6..2f6abe22 100644 --- a/src/net.md +++ b/src/net.md @@ -544,18 +544,8 @@ quick_main!(run); [![std-badge]][std] [![cat-net-badge]][cat-net] -Give the OS the responsibility to pick an unused [registered port]. These ports -generally do not require sudo permission to bind to, and can be helpful when -establishing connections with clients in a disposable communication chain. -These ports begin with 1024 and have around 48,000 available. Typically, a -known port is used to initiate the communication and subsequent communication -occurs on the registered port after a handshake process. - -In this example, the port is displayed on the console, and will listen until a -request is made. If you use your browser to test this program, simply enter -the address:port into your location bar and make the request. Because the -program returns nothing, the browser's stop feature can be used to speed things -up. +In this example, the port is displayed on the console, and the program will +listen until a request is made. ```rust, no_run #[macro_use] @@ -590,19 +580,15 @@ quick_main!(run); ``` The `std` library is leveraged to make a well formed IP/port with the -[`SocketAddrV4`] and [`Ipv4Addr`] structs. The loopback address is a special -address that runs only on the local machine, and is available on all machines. - -By passing 0 to the [`TcpListener::bind`], the OS will assign an unused random -port. The address and port that the OS assigns is available using +[`SocketAddrV4`] and [`Ipv4Addr`] structs. An unused random port is requested +by passing 0 to [`TcpListener::bind`]. The assigned address is available via [`TcpListener::local_addr`]. -The rest of the recipe prints out the request made on the socket. -[`TcpListener::accept`] returns a `(`[`TcpStream`], [`SocketAddrV4`]`)` -representing the data from the client, its IP address and port. Reading on the -socket with [`read_to_string`] will wait until the connection is closed which -can be tested with `telnet ip port`. For example, if the program shows -Listening on 127.0.0.1:11500, run +[`TcpListener::accept`] synchronously waits for an incoming connection and +returns a `(`[`TcpStream`], [`SocketAddrV4`]`)` representing the request. +Reading on the socket with [`read_to_string`] will wait until the connection is +closed which can be tested with `telnet ip port`. For example, if the program +shows Listening on 127.0.0.1:11500, run `telnet 127.0.0.1 11500` From 10a14ea102a9d4413d558ce2c6cac74582e911de Mon Sep 17 00:00:00 2001 From: Andy Gauge Date: Fri, 19 May 2017 15:36:09 -0700 Subject: [PATCH 5/5] Removed unused reference --- src/net.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/net.md b/src/net.md index 2f6abe22..5bd4164c 100644 --- a/src/net.md +++ b/src/net.md @@ -635,7 +635,6 @@ After sending data in telnet press `ctrl-]` and type `quit`. [`RequestBuilder::json`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.json [`RequestBuilder::send`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.send [`read_to_string`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_string -[registered port]: https://en.wikipedia.org/wiki/Registered_port [`String`]: https://doc.rust-lang.org/std/string/struct.String.html [`serde::Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html [`serde_json::json!`]: https://docs.rs/serde_json/*/serde_json/macro.json.html