日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Rust中的信號處理:Unix信號 vs 信號服務器

來源: 責編: 時間:2024-04-02 17:19:16 172觀看
導讀如果你正在運行一個服務器,假設服務器需要從磁盤讀取一些文件,比如證書或密鑰。證書經常會發生變化,因此你的服務器必須重新加載它們。如何告訴服務器重新加載這些文件?傳統的方法是使用Unix信號,你的服務器偵聽特定的信號

如果你正在運行一個服務器,假設服務器需要從磁盤讀取一些文件,比如證書或密鑰。證書經常會發生變化,因此你的服務器必須重新加載它們。如何告訴服務器重新加載這些文件?3Sj28資訊網——每日最新資訊28at.com

傳統的方法是使用Unix信號,你的服務器偵聽特定的信號,如SIGUSR1(用戶定義的信號#1)或SIGHUP(掛起信號),并且可以在接收到信號時執行你編寫的任何代碼。因此,你的服務器等待適當的信號,接收它,然后重新加載證書。3Sj28資訊網——每日最新資訊28at.com

這種方法工作得很好,但是在實際應用中出現了一些可用性的問題。使用單獨的一個http服務器來處理信號會更好。3Sj28資訊網——每日最新資訊28at.com

下面我們先來看一下使用Unix信號的例子,然后我們使用服務器處理信號來改進這個例子。3Sj28資訊網——每日最新資訊28at.com

首先,我們先創建一個Rust項目:3Sj28資訊網——每日最新資訊28at.com

cargo new signals-servers

3Sj28資訊網——每日最新資訊28at.com

在Cargo.toml文件中加入以下依賴項:3Sj28資訊網——每日最新資訊28at.com

[dependencies]axum = "0.7.2"tokio = { version = "1.25.0", features = ["macros", "rt-multi-thread", "signal"] }

在項目根目錄下創建一個cert.pem文件,內容隨便寫,只是為了演示。3Sj28資訊網——每日最新資訊28at.com

3Sj28資訊網——每日最新資訊28at.com

3Sj28資訊網——每日最新資訊28at.com

Unix信號處理

我們看一個完整的服務器偵聽信號的示例,當你啟動你的服務器時,也啟動一個異步任務(或進程,或線程)來監聽這個信號,當接收到信號時,重新加載證書。3Sj28資訊網——每日最新資訊28at.com

創建一個src/bin/unix_signal.rs文件,代碼如下:3Sj28資訊網——每日最新資訊28at.com

use axum::{routing::get, Router};use std::process;use tokio::signal::unix::{signal, SignalKind};#[tokio::main]async fn main() {    let _cert = std::fs::read_to_string("cert.pem");    println!("已加載證書,正在啟動web服務器");    println!("PID: {}", process::id());    tokio::select! {        _ = start_normal_server(8080) => {            println!("Web服務器關閉")        }        _ = listen_for_reload(SignalKind::hangup()) => {            println!("信號監聽器停止")        }    }}async fn start_normal_server(port: u32) {    // 構建我們的應用程序    let app = Router::new().route("/hello", get(|| async { "Hello, world!" }));    let addr = format!("127.0.0.1:{port}");    let listener = tokio::net::TcpListener::bind(addr).await.unwrap();    axum::serve(listener, app).await.unwrap();}async fn listen_for_reload(signal_kind: SignalKind) -> Result<(), std::io::Error> {    // 監聽信號    let mut stream = signal(signal_kind)?;    loop {        stream.recv().await;        match std::fs::read_to_string("cert.pem") {            Ok(_) => eprintln!("重新加載證書成功"),            Err(e) => eprintln!("無法重新加載證書: {e}"),        }    }}

3Sj28資訊網——每日最新資訊28at.com

運行如下命令啟動服務器:3Sj28資訊網——每日最新資訊28at.com

cargo run --bin unix_signal已加載證書,正在啟動web服務器PID: 41945

3Sj28資訊網——每日最新資訊28at.com

然后打開一個新的終端,輸入以下命令:3Sj28資訊網——每日最新資訊28at.com

kill -s sighup 41945

3Sj28資訊網——每日最新資訊28at.com

這是服務器的日志如下:3Sj28資訊網——每日最新資訊28at.com

已加載證書,正在啟動web服務器PID: 41945重新加載證書成功

3Sj28資訊網——每日最新資訊28at.com

這是可行的,但對于發送信號的人來說,這不是一個很好的用戶體驗。假設你是SRE或系統管理員,當需要重新加載服務器證書時,首先查找進程的PID,并使用kill -s sighup pid發送信號。3Sj28資訊網——每日最新資訊28at.com

服務器可能重新加載了,但也許它沒有,可能出現了錯誤,例如新證書無效,或者服務器沒有讀取新證書的權限。系統管理員如何知道是否發生了這種情況?他們應該檢查一下服務器的日志,但這需要切換窗口,或者打開一個不同的程序。3Sj28資訊網——每日最新資訊28at.com

這不是一個很好的用戶體驗。通常,當你運行命令時,希望得到一些反饋。但是當你發送Unix信號時,終端不會給你任何響應。你必須查找服務器的日志并檢查它們,以確保重新加載成功完成。閱讀一個不熟悉的程序日志是很困難的,特別是當日志中有很多其他錯誤時。3Sj28資訊網——每日最新資訊28at.com

Unix信號的主要問題是,它們讓用戶向進程發出信號,但程序不向用戶發送響應。3Sj28資訊網——每日最新資訊28at.com

3Sj28資訊網——每日最新資訊28at.com

3Sj28資訊網——每日最新資訊28at.com

更好的方法:信號服務器

因此,我們希望進程接受請求(“重新加載您的證書”),并響應(“是的,它成功了”或“它失敗了,原因如下”)。這聽起來很熟悉——它只是一個普通的請求-響應協議。沒有必要重新發明輪子——我們可以在這個過程中啟動第二個小HTTP服務器。3Sj28資訊網——每日最新資訊28at.com

創建一個src/bin/http_signal.rs文件,代碼如下:3Sj28資訊網——每日最新資訊28at.com

use axum::{    http::StatusCode,    response::IntoResponse,    routing::{get, post},    Router,};#[tokio::main]async fn main() {    let _cert = std::fs::read_to_string("cert.pem");    println!("已加載證書,正在啟動web服務器");    tokio::select! {        _ = start_normal_server(8080) => {            println!("Web服務器關閉")        }        _ = start_control_server(3000) => {            println!("信號服務器關閉")        }    }}async fn start_normal_server(port: u32) {    // 構建我們的應用程序    let app = Router::new().route("/hello", get(|| async { "Hello, world!" }));    let addr = format!("127.0.0.1:{port}");    let listener = tokio::net::TcpListener::bind(addr).await.unwrap();    axum::serve(listener, app).await.unwrap();}async fn start_control_server(port: u32) {    // 構建信號控制服務器    let app: Router = Router::new().route(        "/reload_certs",        post(|| async {            println!("重新加載證書");            match std::fs::read_to_string("cert.pem") {                Ok(_) => "重新加載證書成功".into_response(),                Err(e) => {                    let error = format!("無法重新加載證書: {e}");                    eprintln!("{error}");                    let resp = (StatusCode::INTERNAL_SERVER_ERROR, error);                    resp.into_response()                }            }        }),    );    let addr = format!("127.0.0.1:{port}");    let listener = tokio::net::TcpListener::bind(addr).await.unwrap();    axum::serve(listener, app).await.unwrap();}

3Sj28資訊網——每日最新資訊28at.com

對于SRE或系統管理員來說,這是一個更好的用戶體驗。使用如下命令重新加載證書:3Sj28資訊網——每日最新資訊28at.com

$ curl -X POST 0.0.0.0:3000/reload_certs重新加載證書成功%

如果沒有找到證書,會立即得到有關錯誤的反饋:3Sj28資訊網——每日最新資訊28at.com

$ curl -X POST 0.0.0.0:3000/reload_certs無法重新加載證書: No such file or directory (os error 2)

3Sj28資訊網——每日最新資訊28at.com

3Sj28資訊網——每日最新資訊28at.com

總結

如果你的程序不需要HTTP或網絡,那么引入一個完整的HTTP框架來監聽信號可能有點多余。因此,根據程序的大小,以及系統管理員的需求或SRE團隊的大小,來決定是否添加HTTP服務器,因為這對于管理流程的人員和軟件來說,它有更好的用戶體驗。3Sj28資訊網——每日最新資訊28at.com

3Sj28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-80844-0.htmlRust中的信號處理:Unix信號 vs 信號服務器

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 2024年最受歡迎的十個 Vue.js UI 庫

下一篇: 我們一起聊聊如何三分鐘學會異步任務基礎

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 漳平市| 股票| 乌拉特中旗| 新巴尔虎左旗| 道真| 罗源县| 白朗县| 洪泽县| 庆阳市| 东兴市| 弋阳县| 新昌县| 英山县| 泗洪县| 昔阳县| 滨海县| 阳高县| 嫩江县| 马关县| 晴隆县| 湖北省| 固始县| 佛坪县| 武山县| 长泰县| 福清市| 崇文区| 白山市| 湘潭县| 任丘市| 宁河县| 寿阳县| 准格尔旗| 大姚县| 河北区| 东明县| 长治市| 临沭县| 金乡县| 靖西县| 吉首市|