
Greetings everyone, here comes another [Rust lang series](https://steemit.com/created/rust-series) episode. Today we will try to create simple TCP server in Rust that will listen at given port and return simple text greeting when connected. Each connection will be handled in special thread.
## TCP server simplified implementation
We will use only API from standard library, API related to TCP protocol is part of networking **std::net** module. Let's take a look at code at first before we break it down.
```rust
use std::io::Write;
use std::net::TcpListener;
use std::thread;
fn main() {
let ip_and_port = "127.0.0.1:1234";
let listener = TcpListener::bind(ip_and_port).unwrap();
println!("listening on port 1234 on http://localhost:1234");
for stream in listener.incoming() {
thread::spawn(|| {
let mut stream = stream.unwrap();
stream.write(b"Hi to all Steemiters!\r\n").unwrap();
});
}
}
```
### Output
When you open your browser and open http://localhost:1234 address you'll see this message
```
Hi to all Steemiters!
```
You can also check connection from command-line with tools curl or whatever is provided on your OS.
```
curl localhost:1234
# output
Hi to all Steemiters!
curl: (56) Recv failure: Connection reset by peer
```
### Breaking down
Let's analyze the source code a bit:
First we set ip address and port, we set it to localhost (127.0.0.1) and port to 1234.
**std::io::Write** provides write method for TcpStream
**std::net::TcpListener** is basic building component for TCP socket server
**bind()** method creates TcpListener and binds it to given port
**incomming()** iterator over received connections
**thread::spawn()** new thread is created and executes code each TCP stream (connection)
**write()** sends data to TCPStream
## Version with proper error handling
Of course previous version doesn't solve issue handling that can occur on multiple places and just terminate main thread when something bad occurs. Let's try to implement something the a better care for potential errors. Possible implementation could look like this for example.
```rust
use std::io::Write;
use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;
fn create_server() -> Option<TcpListener> {
let ip_and_port = "127.0.0.1:1234";
let res = TcpListener::bind(ip_and_port);
match res {
Ok(listener) => return Some(listener),
Err(err) => {
println!("Cannot create server: - {}", err.to_string());
None
}
}
}
fn handle_incoming_stream(mut stream: TcpStream) {
thread::spawn(move || {
let write_res = stream.write(b"Hi to all Steemiters!\r\n");
if let Err(err) = write_res {
println!("Cannot send data - {}", err.to_string());
} else {
println!("Response sent OK");
}
});
}
fn main() {
let server_result = create_server();
if let Some(listener) = server_result {
println!("listening on port 1234 on http://localhost:1234");
for stream_res in listener.incoming() {
if let Ok(mut stream) = stream_res {
handle_incoming_stream(stream);
} else if let Err(err) = stream_res {
println!("Stream error - {}", err.to_string());
}
}
}
}
```
### Output
When you see this application multiple times you can see for example this error properly handled.
```
Cannot create server: - Address already in use (os error 98)
Application finished!
```
### Breaking down
Code is just split to mutliple functions to separate concerns and handling related errors. TcpListener and TcpStreams operations returns **std::io::Result** that we handled on proper places. But in general there is nothing new that should be explained.
## Postfix
That's all for now, thank you for your appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). May Jesus bless your programming skills, use them wisely and see you next time.
Meanwhile you can also check the official documentation for additional related information:
* https://doc.rust-lang.org/std/net/
* https://doc.rust-lang.org/std/net/struct.TcpStream.html
* https://doc.rust-lang.org/std/net/struct.TcpListener.html