-
Notifications
You must be signed in to change notification settings - Fork 302
Added networking example to listen on random socket using tcp/ip #137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
18e35d0
0436206
e5c7db1
25b53f7
eaf2abc
10a14ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
<a name="ex-url-parse"/> | ||
|
@@ -537,6 +538,75 @@ fn run() -> Result<()> { | |
quick_main!(run); | ||
``` | ||
|
||
[ex-random-port-tcp]: #ex-random-port-tcp | ||
<a name="ex-random-port-tcp"></a> | ||
## 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This paragraph is overly word and redundant with later telnet testing one. |
||
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 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) = listener.accept()?; //block until requested | ||
println!("Connection received! {:?} is sending data.", addr); | ||
let mut input = String::new(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the connection is already accepted here. I would suggest printing |
||
// 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(()) | ||
} | ||
|
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rather not try to educate the readers on what the loopback interface is. I would just stick to stating that code is listening on the loopback interface (possibly with hyperlink to some authoritative resource) |
||
|
||
By passing 0 to the [`TcpListener::bind`], the OS will assign an unused random | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest rewording it in a more concise manner e.g:
|
||
port. The address and port that the OS assigns is available using | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nit. Please do not mix tenses. Use present/past/future throughout the whole text. |
||
[`TcpListener::local_addr`]. | ||
|
||
The rest of the recipe prints out the request made on the socket. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would remove this sentence and modify the following ones to reflect what is going one step by step. |
||
[`TcpListener::accept`] returns a `(`[`TcpStream`], [`SocketAddrV4`]`)` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The key fact about accept is that it synchronously waits for an incoming connection and returns the pair There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'an incoming connection is waited synchronously by TcpListener::accept` <- another case where passive isn't the best. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep |
||
representing the data from the client, its IP address and port. Reading on the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, so I'm going to take out the details about what the tuple is and call it the request. I think the links do a good job of explaining the details. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this work: [ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks excellent 👍 |
||
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`. | ||
<!-- Categories --> | ||
|
||
[cat-encoding-badge]: https://img.shields.io/badge/-encoding-red.svg | ||
|
@@ -552,6 +622,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 | ||
|
@@ -577,8 +649,15 @@ quick_main!(run); | |
[`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 | ||
[`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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that you have put a lot of effort into this section but I would rather not educate readers on CS/Networking basics. We can safely assume that reader understands these concepts and came here only for the rust snippet and its very brief textual description (that would ideally be 2-4 sentences). I would suggest dropping this paragraph completely.