This repository contains the Rust rewrites of examples that are explained in Beej's Guide to Network Programming.
- Requirements
- Implementation
- Usage
- Examples
- Section 5.1 -
getaddrinfo()- Prepare to Launch! - Section 5.2 -
socket()- Get the File Descriptor! - Section 5.3 -
bind()- What Port Am I On? - Section 5.4 -
connect()- Hey, you! - Section 5.5 -
listen()- Will Somebody Please Call Me? - Section 5.6 -
accept()- "Thank you for calling port 3490." - Section 5.7 -
send() and recv()- Talk to me, baby! - Section 5.8 -
sendto() and recvfrom()- Talk to me, DGRAM-style - Section 5.9 -
close() and shutdown()- Get outta my face! - Section 5.10 -
getpeername()- Who are you? - Section 5.11 -
gethostname()- Who am I? - Section 6.1 & 6.2 - A Simple Stream Server & Client
- Section 6.3 - Datagram Sockets
- Section 7.1 - Blocking
- Section 7.2 -
poll()- Synchronous I/O Multiplexing - Section 7.3 -
select()- Synchronous I/O Multiplexing, Old School - Section 7.7 - Broadcast Packets - Hello, World!
- Section 5.1 -
- Notes
- LICENSE
The Rust toolchain needs to be installed on the host to run the examples. It can be installed from here.
I tried to keep the examples as close to the original implementations as possible, therefore the project only uses the libc crate for each example.
As a result, unsafe blocks are heavily used throughout the project.
The only exception to this decision is the C examples of pollserver and selectserver.
These examples do more unsafe operations than the underlying syscalls that are basically not accepted by safe Rust (e.g. mutating a collection while traversing).
Therefore, in order to keep unsafe blocks under control, additional structures are used for these, which made them a bit more verbose compared to their C counterparts.
Some examples can be run standalone, but some require multiple shell sessions. Before running the examples, I would recommend to check out the long help text first.
$ cargo run -- --help
# Usage: bjrs <COMMAND>
#
# Commands:
# syscall Chapter 5 - System Calls or Bust
# stream Section 6.1 & 6.2 - A Simple Stream Server & Client
# dgram Section 6.3 - Datagram Sockets
# techniques Chapter 7 - Slightly Advanced Techniques
# help Print this message or the help of the given subcommand(s)
#
# Options:
# -h, --help Print help
# -V, --version Print version$ cargo run -- syscall --help
# Chapter 5 - System Calls or Bust
#
# Usage: bjrs syscall <COMMAND>
#
# Commands:
# getaddrinfo Section 5.1 - `getaddrinfo()` - Prepare to Launch!
# socket Section 5.2 - `socket()` - Get the File Descriptor!
# bind Section 5.3 - `bind()` - What Port Am I On?
# connect Section 5.4 - `connect()` - Hey, you!
# listen Section 5.5 - `listen()` - Will Somebody Please Call Me?
# accept Section 5.6 - `accept()` - "Thank you for calling port 3490."
# send Section 5.7 - `send() and recv()` - Talk to me, baby!
# recv Section 5.7 - `send() and recv()` - Talk to me, baby!
# sendto Section 5.8 - `sendto() and recvfrom()` - Talk to me, DGRAM-style
# recvfrom Section 5.8 - `sendto() and recvfrom()` - Talk to me, DGRAM-style
# close Section 5.9 - `close() and shutdown()` - Get outta my face!
# shutdown Section 5.9 - `close() and shutdown()` - Get outta my face!
# getpeername Section 5.10 - `getpeername()` - Who are you?
# gethostname Section 5.11 - `gethostname()` - Who am I?
# help Print this message or the help of the given subcommand(s)
#
# Options:
# -h, --help Print helpHere is an example where it needs manual preparation:
$ cargo run -- stream server --help
# Section 6.1 - A Simple Stream Server
#
# To test this example:
#
# Run this command to start our "TCP" server. In a separate terminal session, run the client command `bjrs stream client`. Observe that the server sends the message "Hello world!" to the client.
#
# Usage: bjrs stream server
#
# Options:
# -h, --help
# Print help (see a summary with '-h')Some examples in Beej's book are in their own C files and some of them are inlined to .md pages.
Here is how the examples in this project are mapped to Beej's book. The inlined examples are shown with md prefix, and C files are shown as is:
For socket(), Beej shows the usage via a pseudocode. In here, I tried to build on getaddrinfo() to showcase how a basic socket() call can be made.
md-bind-port-reuse -> bind.rs (fn reuse_port)
md-sendto-synopsis -> sendto.rs
md-recvfrom-synopsis -> recvfrom.rs
md-shutdown-synopsis -> shutdown.rs
md-getpeername-synopsis -> getpeername.rs
md-gethostname-synopsis -> gethostname.rs
selectserver.c -> selectserver.rs
broadcaster.c -> broadcaster.rs
If you check the very first example and compare it to the last ones, you will see that there are quite a bit differences regarding how the unsafe operations are executed, such as:
- The contents of
unsafeblocks, - The contents of
SAFETYcomments, - The countless casts done between pointers and types themselves.
This results in an inconsistency between the examples, and I intentionally kept this fact. It shows how unsafe Rust effects the thought process the more you write, which is pleasant to reveal.
This work is dual-licensed under Apache 2.0 and GPL 2.0 (or any later version). You can choose between one of them if you use this work.
SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later