-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
std: add example apps for tokio and socket2
- Loading branch information
1 parent
5393843
commit 3fd8485
Showing
6 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} | ||
}); | ||
} | ||
} |