精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

文盤Rust--把程序作為守護進程啟動

jf_wN0SrCdH ? 來源:Rust語言中文社區 ? 作者:Rust語言中文社區 ? 2022-11-07 10:22 ? 次閱讀

當我們寫完一個服務端程序,需要上線部署的時候,或多或少都會和操作系統的守護進程打交道,畢竟誰也不希望shell關閉既停服。今天我們就來聊聊這個事兒。

最早大家部署應用的通常操作是 “nohup xxxx &”,別說像weblogic 或者其他java 容器有啟動腳本,里面其實也差不多;很喜歡 nginx的 -d 參數,或者像redis 配置文件里可以指定是否以守護進程啟動。看起來很優雅。

那么,使用rust 寫一個服務端程序能不能優雅的使用一個參數指定應用 daemon 模式啟動,同時使用stop 方式優雅的停機呢?我們通過一個例子來說說基本的實現方式。

實例代碼依然集成在[interactcli-rs](https://github.com/jiashiwen/interactcli-rs)工程中。

首先來模擬一個啟動的服務進程 /src/server/server.rs

```rust
pub fn start(prefix: String) {
    for i in 0..1000 {
        println!("{}", prefix.clone() + &i.to_string());
        thread::sleep(Duration::from_secs(1));
    }
}
```
程序每秒輸出一個字符串,持續999秒,這個時間足夠驗證實驗結果了。

后臺啟動有兩個實現,分別是利用[fork](github.com/immortal/fork) 或 [daemonize](github.com/knsd/daemonize),這兩個crate 實現原理類似,但在使用上稍有不同。

/src/cmd/cmdserver.rs,構建了兩個啟動子命令,分別來調用 fork 和 daemonize的守護進程啟動實現。

```rust
pub fn new_server_cmd() -> Command {
    clap::new("server")
        .about("server")
        .subcommand(server_start_byfork())
        .subcommand(server_start_bydaemonize())
}


pub fn server_start_byfork() -> Command {
    clap::new("byfork")
        .about("start daemon by fork crate")
        .arg(
            Arg::new("daemon")
                .short('d')
                .long("daemon")
                .action(ArgAction::SetTrue)
                .help("start as daemon")
                .required(false),
        )
}
pub fn server_start_bydaemonize() -> Command {
    clap::new("bydaemonize")
        .about("start daemon by daemonize crate")
        .arg(
            Arg::new("daemon")
                .short('d')
                .long("daemon")
                .action(ArgAction::SetTrue)
                .help("start as daemon")
                .required(false),
        )
}
```
server 的子命令 byfork 啟動 通過 fork 實現的功能,bydaemonize 則調用通過 daemonize 的功能實現。

命令解析的代碼在 /src/cmd/rootcmd.rs 文件中。

先來看看基于 fork 的實現:

```rust
if let Some(startbyfork) = server.subcommand_matches("byfork") {
    println!("start by fork");
    if startbyfork.get_flag("daemon") {
        let args: Vec = env::args().collect();
        if let Ok(Fork::Child) = daemon(true, false) {
            // 啟動子進程
            let mut cmd = Command::new(&args[0])
            for idx in 1..args.len() {
                let arg = args.get(idx).expect("get cmd arg error!");
                // 去除后臺啟動參數,避免重復啟動
                if arg.eq("-d") || arg.eq("-daemon") {
                    continue;
                }
                cmd.arg(arg);
            
            let child = cmd.spawn().expect("Child process failed to start.");
            fs::write("pid", child.id().to_string()).unwrap();
            println!("process id is:{}", std::id());
            println!("child id is:{}", child.id());
        }
        println!("{}", "daemon mod");
        process::exit(0);
    }
    start("by_fork:".to_string());
}


```

首先,通過 Fork::daemon 函數派生出一個子進程;然后解析一下當前命令,去掉 -d 參數,構建一個啟動命令,子命令啟動,退出父進程。這基本符合操作系統創建守護進程的過程 -- 兩次 fork。

再來看看基于 daemonize 的實現:

```rust
if let Some(startbydaemonize) = server.subcommand_matches("bydaemonize") {
            println!("start by daemonize");
            let base_dir = env::current_dir().unwrap();
            if startbydaemonize.get_flag("daemon") {
                let stdout = File::create("/tmp/daemon.out").unwrap();
                let stderr = File::create("/tmp/daemon.err").unwrap();


                println!("{:?}", base_dir);


                let daemonize = Daemonize::new()
                    .pid_file("/tmp/test.pid") // Every method except `new` and `start`
                    .chown_pid_file(true) // is optional, see `Daemonize` documentation
                    .working_directory(base_dir.as_path()) // for default behaviour.          
                    .umask(0o777) // Set umask, `0o027` by default.
                    .stdout(stdout) // Redirect stdout to `/tmp/daemon.out`.
                    .stderr(stderr) // Redirect stderr to `/tmp/daemon.err`.
                    .privileged_action(|| "Executed before drop privileges");


                match daemonize.start() {
                    Ok(_) => {
                        println!("Success, daemonized");
                    }
                    Err(e) => eprintln!("Error, {}", e),
                }
            }
            println!("pid is:{}", std::id());
            fs::write("pid", process::id().to_string()).unwrap();
            start("by_daemonize:".to_string());
        }
```

首先獲取當前的工作目錄,默認情況下 daemonize 會將工作目錄設置為 "/",為了避免權限問題,我們獲取當前目錄作為守護進程的工作目錄。不知道是什么原因,在配置了pid_file 后,啟動守護進程時并沒在文件中有記錄 pid。不過也沒關系,我們可以在外部獲取并記錄守護進程的pid。

兩種方式啟動的守護進程均可在關閉shell的情況下維持進程運行。

從實現上來講,不論是 fork 還是 daemonize 都是 通過unsafe 方式調用了 libc api,類 unix 系統大多跑起來沒問題,windows 系統作者沒有驗證。

本期關于守護進程的話題就聊到這兒。

咱們下期見。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 程序
    +關注

    關注

    115

    文章

    3720

    瀏覽量

    80357
  • Rust
    +關注

    關注

    1

    文章

    226

    瀏覽量

    6497

原文標題:文盤Rust -- 把程序作為守護進程啟動

文章出處:【微信號:Rust語言中文社區,微信公眾號:Rust語言中文社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    深度無多配置一些經驗心得

    的情況下,在安裝守護驅動前,個人一些建議,首先我們要確保intel 和amd的機器都能正常無啟動。大家都知道,網吧做母盤時,遇到在intel機器上做完的母盤拿到amd機器上藍屏的情況,這個本身是intel
    發表于 07-19 09:22

    Linux守護進程

    )是不能卸載的,這對以后的使用會造成諸多的麻煩(如系統由于某種原因要進入單用戶模式)。因此,通常的做法是讓“/”作為守護進程的當前工作目錄,這樣就可以避免上述問題。當然,如有特殊需要,也可以
    發表于 08-22 09:17

    【Linux學習雜談】之守護進程以及簡單創建

    首先我們需要了解一下什么叫做守護進程,以及我們為什么需要這樣的進程。我們知道當我們寫一個簡單的程序的時候我們知道,這個程序比如說printf
    發表于 09-27 13:28

    升級程序作為一個單獨進程的方法

    步驟:升級程序作為一個單獨的進程1. 定時請求2. 對比版本號(使用正則匹配或字符串提取主版本號、次版本號、末版本號)3. 當前版本號較小時下載升級資源包4. 備份當前版本程序5. 解
    發表于 12-17 07:33

    Xtensa調試器守護進程在Linux中不工作的原因?怎么解決?

    試器守護進程” 中,我從路徑 /opt/xtensa/XtDevTools/downloads/RI-2021.8/tools/ 安裝 xt-ocd-14.08-linux64-installer。安裝
    發表于 03-21 08:39

    iny Linux有沒有辦法設置ssh或telnet守護進程可以在啟動后自動執行?

    Linux 有沒有辦法設置ssh 或telnet 守護進程可以在啟動后自動執行? 我們想在不通過控制臺的情況下使用 ssh 或 telnet 連接到微型 Linux。
    發表于 04-23 06:16

    守護進程的初級教程

    守護進程的初級教程,淺顯易懂,適合初學者
    發表于 06-17 16:16 ?0次下載

    Linux守護進程詳解

    較長的進程,通常獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。守護進程常常在系統引導載入時啟動,在系統關閉時終止。Linux有很多系統服務,大多數服務都是通過
    發表于 10-18 14:24 ?0次下載
    Linux<b class='flag-5'>守護</b><b class='flag-5'>進程</b>詳解

    linux守護進程實例

      今天完成一個守護進程實驗。  1 熟悉守護進程編寫和調試(系統日志)  2 編寫多進程
    發表于 04-02 14:42 ?356次閱讀

    U啟動盤制作工具應用程序免費下載

    本文檔的主要內容詳細介紹的是U啟動盤制作工具應用程序免費下載。
    發表于 04-24 08:00 ?5次下載
    U<b class='flag-5'>盤</b><b class='flag-5'>啟動盤</b>制作工具應用<b class='flag-5'>程序</b>免費下載

    Linux 安全模塊:守護進程和套接字

    守護進程通常是在后臺觀察操作以等待狀態、服務于特定子系統并確定整個系統的操作規則的實用程序。例如,一個守護進程被配置為監控打印服務的狀態。
    發表于 08-26 10:01 ?596次閱讀

    Rust -- rust連接oss

    我們以 [S3 sdk](https://github.com/awslabs/aws-sdk-rust)為例來說說基本的連接與操作,作者驗證過aws、京東云、阿里云。主要的增刪改查功能沒有什么差別。
    的頭像 發表于 05-12 16:18 ?491次閱讀

    Rust -- tokio綁定cpu實踐

    )。core_affinity_rs是一個用于管理CPU親和力的Rust crate。目前支持Linux、Mac OSX和Windows。官方宣稱支持多平臺,本人只做了linux 操作系統的測試。
    的頭像 發表于 06-11 15:32 ?478次閱讀
    <b class='flag-5'>文</b><b class='flag-5'>盤</b><b class='flag-5'>Rust</b> -- tokio綁定cpu實踐

    程序進程和線程的區別

    什么是進程 1、進程和線程的區別 進程是指正在運行的程序,它擁有獨立的內存空間和系統資源,不同進程之間的數據不共享。
    的頭像 發表于 06-22 11:39 ?533次閱讀
    <b class='flag-5'>程序</b>中<b class='flag-5'>進程</b>和線程的區別

    Linux中如何編寫守護進程程序

    的一種進程,它們一般在系統啟動時開始運行,除非強行終止,否則直到系統關機都會保持運行。與守護進程相比,普通進程都是在用戶登錄或運行
    的頭像 發表于 10-07 17:12 ?532次閱讀
    Linux中如何編寫<b class='flag-5'>守護</b><b class='flag-5'>進程</b><b class='flag-5'>程序</b>