简单网络通信

wasmedge_wasi_socket 让 Rust 开发者可以创建简单的网络通信应用程序,然后将它编译为在 WasmEdge Runtime 中运行的 WebAssembly。WasmEdge 的一项关键特性便是对非阻塞套接字的支持,可以让一个单线程的 WASM 应用程序处理并发的网络请求。比如,当程序在等待一个连接传输的数据时,它可以开始或处理另一个连接。

在本章节中,我们将从一个简单的 HTTP 客户端以及服务器示例开始。然后在下个章节中,我们会介绍更为复杂的非阻塞示例。

HTTP 客户端示例

HTTP 客户端的源代码 如下。

1. use wasmedge_http_req::request;

3. fn main() {
4. let mut writer = Vec::new(); //container for body of a response
5. let res = request::get("http://127.0.0.1:1234/get", &mut writer).unwrap();

7. println!("GET");
8. println!("Status: {} {}", res.status_code(), res.reason());
9. println!("Headers {}", res.headers());
10. println!("{}", String::from_utf8_lossy(&writer));

12. let mut writer = Vec::new(); //container for body of a response
13. const BODY: &[u8; 27] = b"field1=value1&field2=value2";
14. // let res = request::post("https://httpbin.org/post", BODY, &mut writer).unwrap();
15. // no https , no dns
16. let res = request::post("http://127.0.0.1:1234/post", BODY, &mut writer).unwrap();

18. println!("POST");
19. println!("Status: {} {}", res.status_code(), res.reason());
20. println!("Headers {}", res.headers());
21. println!("{}", String::from_utf8_lossy(&writer));
22. }

使用如下命令来编译 Rust 程序。

cargo build --target wasm32-wasi --release

使用如下命令在 WasmEdge 中运行程序。

wasmedge target/wasm32-wasi/release/http_client.wasm

HTTP 服务器示例

HTTP 服务器的源代码 如下。

1. use bytecodec::DecodeExt;
2. use httpcodec::{HttpVersion, ReasonPhrase, Request, RequestDecoder, Response, StatusCode};
3. use std::io::{Read, Write};
4. #[cfg(feature = "std")]
5. use std::net::{Shutdown, TcpListener, TcpStream};
6. #[cfg(not(feature = "std"))]
7. use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};

9. fn handle_http(req: Request<String>) -> bytecodec::Result<Response<String>> {
10. Ok(Response::new(
11. HttpVersion::V1_0,
12. StatusCode::new(200)?,
13. ReasonPhrase::new("")?,
14. format!("echo: {}", req.body()),
15. ))
16. }

18. fn handle_client(mut stream: TcpStream) -> std::io::Result<()> {
19. let mut buff = [0u8; 1024];
20. let mut data = Vec::new();

22. loop {
23. let n = stream.read(&mut buff)?;
24. data.extend_from_slice(&buff[0..n]);
25. if n < 1024 {
26. break;
27. }
28. }

30. let mut decoder =
31. RequestDecoder::<httpcodec::BodyDecoder<bytecodec::bytes::Utf8Decoder>>::default();

33. let req = match decoder.decode_from_bytes(data.as_slice()) {
34. Ok(req) => handle_http(req),
35. Err(e) => Err(e),
36. };

38. let r = match req {
39. Ok(r) => r,
40. Err(e) => {
41. let err = format!("{:?}", e);
42. Response::new(
43. HttpVersion::V1_0,
44. StatusCode::new(500).unwrap(),
45. ReasonPhrase::new(err.as_str()).unwrap(),
46. err.clone(),
47. )
48. }
49. };

51. let write_buf = r.to_string();
52. stream.write(write_buf.as_bytes())?;
53. stream.shutdown(Shutdown::Both)?;
54. Ok(())
55. }

57. fn main() -> std::io::Result<()> {
58. let port = std::env::var("PORT").unwrap_or(1234.to_string());
59. println!("new connection at {}", port);
60. let listener = TcpListener::bind(format!("0.0.0.0:{}", port))?;
61. loop {
62. let _ = handle_client(listener.accept()?.0);
63. }
64. }

使用如下命令来编译 Rust 程序。

cargo build --target wasm32-wasi --release

使用如下命令在 WasmEdge 中运行程序。

$ wasmedge target/wasm32-wasi/release/http_server.wasm new connection at 1234

你可以用 curl 发送一个 HTTP 请求,来测试 HTTP 服务器。

$ curl -d "name=WasmEdge" -X POST http://127.0.0.1:1234 echo: name=WasmEdge