iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Software Development

Rust 學得動嗎系列 第 18

[Day 18] Rust 在網路程式設計中的應用

  • 分享至 

  • xImage
  •  

今天,我們來學習 Rust 在網路程式設計中的應用,如何利用 Rust 建構高效能的網路服務與實現網路協議。Rust 的內存安全性與高效能特性,使其成為開發穩定且高效網路應用的理想選擇。

1. 使用 tokio 建立非同步網路服務

Tokio 是 Rust 生態系統中最流行的非同步運行時之一,特別適合用於網路程式設計。

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;

    loop {
        let (mut socket, _) = listener.accept().await?;
        
        tokio::spawn(async move {
            let mut buf = [0; 1024];

            loop {
                let n = match socket.read(&mut buf).await {
                    Ok(n) if n == 0 => return,
                    Ok(n) => n,
                    Err(e) => {
                        eprintln!("無法讀取資料: {}", e);
                        return;
                    }
                };

                if let Err(e) = socket.write_all(&buf[0..n]).await {
                    eprintln!("無法寫入資料: {}", e);
                    return;
                }
            }
        });
    }
}

2. 使用 hyper 實現 HTTP 服務器

Hyper 是一個快速且正確的 HTTP 實現庫,非常適合用於建立 Web 服務。

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use std::convert::Infallible;
use std::net::SocketAddr;

async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new(Body::from("Hello, World!")))
}

#[tokio::main]
async fn main() {
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(handle))
    });

    let server = Server::bind(&addr).serve(make_svc);

    if let Err(e) = server.await {
        eprintln!("伺服器錯誤: {}", e);
    }
}

3. 使用 tonic 實現 gRPC 服務

gRPC 是一個高效能的 RPC 框架,Tonic 提供了在 Rust 中使用 gRPC 的能力。

use tonic::{transport::Server, Request, Response, Status};

pub mod hello_world {
    tonic::include_proto!("helloworld");
}

use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};

#[derive(Debug, Default)]
pub struct MyGreeter {}

#[tonic::async_trait]
impl Greeter for MyGreeter {
    async fn say_hello(
        &self,
        request: Request<HelloRequest>,
    ) -> Result<Response<HelloReply>, Status> {
        let reply = hello_world::HelloReply {
            message: format!("你好 {}!", request.into_inner().name),
        };
        Ok(Response::new(reply))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse()?;
    let greeter = MyGreeter::default();

    Server::builder()
        .add_service(GreeterServer::new(greeter))
        .serve(addr)
        .await?;

    Ok(())
}

4. 使用 tokio-rustls 實現 TLS 加密

在網路程式設計中,安全性至關重要。Tokio-rustls 提供了非同步 TLS 功能。

use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;
use rustls::{Certificate, PrivateKey, ServerConfig};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cert = Certificate(std::fs::read("cert.pem")?);
    let key = PrivateKey(std::fs::read("key.pem")?);

    let config = ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_single_cert(vec![cert], key)?;

    let acceptor = TlsAcceptor::from(Arc::new(config));
    let listener = TcpListener::bind("127.0.0.1:8443").await?;

    while let Ok((stream, _)) = listener.accept().await {
        let acceptor = acceptor.clone();
        tokio::spawn(async move {
            if let Ok(stream) = acceptor.accept(stream).await {
                // 處理加密連接
            }
        });
    }

    Ok(())
}

5. 使用 reqwest 發送 HTTP 請求

Reqwest 是一個易用的 HTTP 客戶端庫,適合用於發送 HTTP 請求。

use reqwest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = reqwest::get("https://www.rust-lang.org")
        .await?
        .text()
        .await?;

    println!("回應內容長度: {}", response.len());

    Ok(())
}

6. 實現簡單的 UDP 通訊

UDP 通常用於需要低延遲的應用程式,如遊戲或即時流媒體。

use tokio::net::UdpSocket;
use std::io;

#[tokio::main]
async fn main() -> io::Result<()> {
    let socket = UdpSocket::bind("127.0.0.1:8080").await?;
    let mut buf = [0; 1024];

    loop {
        let (len, addr) = socket.recv_from(&mut buf).await?;
        println!("從 {:?} 收到: {:?}", addr, &buf[..len]);

        let len = socket.send_to(&buf[..len], addr).await?;
        println!("發送 {} 位元組到 {:?}", len, addr);
    }
}

結論

Rust 在網路程式設計中有很大的優勢。它的安全性保證和高效能特性使得開發人員能夠建立可靠、高效的網路服務和協議實現。透過豐富的生態系統,Rust 提供了多種工具和庫來處理各種網路程式設計需求,從低層級的 TCP/UDP 操作到高層級的 HTTP 和 gRPC 服務,之前到量化交易公司面試過,他們也在使用Rust打造他們的量化交易系統,比C++安全和穩定,不過Rust市場是的職缺和開發者在台灣還不是很多,是一個可以投資的副語言。


上一篇
[Day 17] Rust 在嵌入式系統開發中的應用
下一篇
[Day 19] Rust 如何操作資料庫
系列文
Rust 學得動嗎30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言