Skip to content

Commit

Permalink
std: add example apps for tokio and socket2
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Aug 23, 2023
1 parent 5393843 commit 3fd8485
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 0 deletions.
122 changes: 122 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ members = [

"apps/std/mio-httpserver",
"apps/std/mio-tcpserver",
"apps/std/tokio-echo",
"apps/std/socket2-echoserver",
]

[profile.release]
Expand All @@ -80,3 +82,5 @@ lto = true
[patch.crates-io]
crate_interface = { path = "crates/crate_interface" }
mio = { git = "https://github.com/arceos-os/mio.git", branch = "arceos" }
tokio = { git = "https://github.com/arceos-os/tokio.git", branch = "arceos" }
socket2 = { git = "https://github.com/arceos-os/socket2.git", branch = "arceos" }
14 changes: 14 additions & 0 deletions apps/std/socket2-echoserver/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "std-socket2-echoserver"
version = "0.1.0"
edition = "2021"
authors = ["scpointer <[email protected]>"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
env_logger = { version = "0.9.3", default-features = false }
socket2 = {version = "0.4" }

[package.metadata.arceos]
features = ["net"]
67 changes: 67 additions & 0 deletions apps/std/socket2-echoserver/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Configuration needed to run this test (in the root Makefile):
//! A=apps/std/socket2-echoserver STD=y NET=y
use socket2::{Domain, Socket, Type};
use std::io::Write;
use std::mem::MaybeUninit;
use std::net::SocketAddr;
use std::str::from_utf8;

const DATA: &[u8] = b"hello world";
const BUF_SIZE: usize = 4096;
const ADDR: &str = "0.0.0.0:5555";

fn main() {
env_logger::init();
test()
}

fn test() {
let mut recv_buffer = [MaybeUninit::<u8>::new(0); BUF_SIZE];
let mut send_buffer = [0u8; BUF_SIZE];

let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
let addr: SocketAddr = ADDR.parse::<SocketAddr>().unwrap();
println!("addr {:#?}", addr);
#[cfg(not(target_os = "arceos"))]
let addr: socket2::SockAddr = addr.into();
socket.bind(&addr).unwrap();
socket.listen(128).unwrap();

println!("---------- socket2 echoserver ----------");
println!("type `nc {}` at another terminal:", ADDR);

loop {
let (mut connection, sockaddr) = loop {
if let Ok(result) = socket.accept() {
break result;
} else {
println!("user got a Err from accept, try again");
}
};
#[cfg(target_os = "arceos")]
println!("Accepted connection from: {}", sockaddr);
#[cfg(not(target_os = "arceos"))]
println!(
"Accepted connection from: {}",
sockaddr.as_socket().unwrap()
);
connection.write_all(DATA).unwrap();

loop {
let n = connection.recv(&mut recv_buffer).unwrap();
if n == 0 {
break;
}
for i in 0..n {
send_buffer[i] = unsafe { recv_buffer[i].assume_init() };
}
let received_data = &send_buffer[..n];
if let Ok(str_buf) = from_utf8(received_data) {
println!("Received data({}B): {}", n, str_buf.trim_end());
connection.write_all(received_data).unwrap();
} else {
println!("Received (none UTF-8) data: {:?}", received_data);
}
}
}
}
13 changes: 13 additions & 0 deletions apps/std/tokio-echo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "std-tokio-echo"
version = "0.1.0"
edition = "2021"
authors = ["Yuekai Jia <[email protected]>"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tokio = { version = "1.29", features = ["macros", "rt", "io-util", "net"] }

[package.metadata.arceos]
features = ["net", "multitask"]
78 changes: 78 additions & 0 deletions apps/std/tokio-echo/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//! A "hello world" echo server with Tokio
//!
//! This server will create a TCP listener, accept connections in a loop, and
//! write back everything that's read off of each TCP connection.
//!
//! Because the Tokio runtime uses a thread pool, each TCP connection is
//! processed concurrently with all other TCP connections across multiple
//! threads.
//!
//! To see this server in action, you can run this in one terminal:
//!
//! make A=apps/std/tokio-echo STD=y NET=y run
//!
//! and in another terminal you can run:
//!
//! cargo run --example connect 127.0.0.1:5555
//!
//! Each line you type in to the `connect` terminal should be echo'd back to
//! you! If you open up multiple terminals running the `connect` example you
//! should be able to see them all make progress simultaneously.
#![warn(rust_2018_idioms)]

use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;

use std::env;
use std::error::Error;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn Error>> {
// Allow passing an address to listen on as the first argument of this
// program, but otherwise we'll just set up our TCP listener on
// 127.0.0.1:5555 for connections.
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "0.0.0.0:5555".to_string());

// Next up we create a TCP listener which will listen for incoming
// connections. This TCP listener is bound to the address we determined
// above and must be associated with an event loop.
let listener = TcpListener::bind(&addr).await?;
println!("Listening on: {}", addr);

loop {
// Asynchronously wait for an inbound socket.
let (mut socket, _) = listener.accept().await?;

// And this is where much of the magic of this server happens. We
// crucially want all clients to make progress concurrently, rather than
// blocking one on completion of another. To achieve this we use the
// `tokio::spawn` function to execute the work in the background.
//
// Essentially here we're executing a new task to run concurrently,
// which will allow all of our clients to be processed concurrently.

tokio::spawn(async move {
let mut buf = vec![0; 1024];

// In a loop, read data from the socket and write the data back.
loop {
let n = socket
.read(&mut buf)
.await
.expect("failed to read data from socket");

if n == 0 {
return;
}

socket
.write_all(&buf[0..n])
.await
.expect("failed to write data to socket");
}
});
}
}

0 comments on commit 3fd8485

Please sign in to comment.