RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

文盤Rust--把程序作為守護(hù)進(jìn)程啟動

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

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

最早大家部署應(yīng)用的通常操作是 “nohup xxxx &”,別說像weblogic 或者其他java 容器有啟動腳本,里面其實(shí)也差不多;很喜歡 nginx的 -d 參數(shù),或者像redis 配置文件里可以指定是否以守護(hù)進(jìn)程啟動??雌饋砗軆?yōu)雅。

那么,使用rust 寫一個服務(wù)端程序能不能優(yōu)雅的使用一個參數(shù)指定應(yīng)用 daemon 模式啟動,同時使用stop 方式優(yōu)雅的停機(jī)呢?我們通過一個例子來說說基本的實(shí)現(xiàn)方式。

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

首先來模擬一個啟動的服務(wù)進(jìn)程 /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));
    }
}
```
程序每秒輸出一個字符串,持續(xù)999秒,這個時間足夠驗(yàn)證實(shí)驗(yàn)結(jié)果了。

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

/src/cmd/cmdserver.rs,構(gòu)建了兩個啟動子命令,分別來調(diào)用 fork 和 daemonize的守護(hù)進(jìn)程啟動實(shí)現(xiàn)。

```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 實(shí)現(xiàn)的功能,bydaemonize 則調(diào)用通過 daemonize 的功能實(shí)現(xiàn)。

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

先來看看基于 fork 的實(shí)現(xiàn):

```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) {
            // 啟動子進(jìn)程
            let mut cmd = Command::new(&args[0])
            for idx in 1..args.len() {
                let arg = args.get(idx).expect("get cmd arg error!");
                // 去除后臺啟動參數(shù),避免重復(fù)啟動
                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 函數(shù)派生出一個子進(jìn)程;然后解析一下當(dāng)前命令,去掉 -d 參數(shù),構(gòu)建一個啟動命令,子命令啟動,退出父進(jìn)程。這基本符合操作系統(tǒng)創(chuàng)建守護(hù)進(jìn)程的過程 -- 兩次 fork。

再來看看基于 daemonize 的實(shí)現(xiàn):

```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());
        }
```

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

兩種方式啟動的守護(hù)進(jìn)程均可在關(guān)閉shell的情況下維持進(jìn)程運(yùn)行。

從實(shí)現(xiàn)上來講,不論是 fork 還是 daemonize 都是 通過unsafe 方式調(diào)用了 libc api,類 unix 系統(tǒng)大多跑起來沒問題,windows 系統(tǒng)作者沒有驗(yàn)證。

本期關(guān)于守護(hù)進(jìn)程的話題就聊到這兒。

咱們下期見。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3785

    瀏覽量

    81001
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    228

    瀏覽量

    6598

原文標(biāo)題:文盤Rust -- 把程序作為守護(hù)進(jìn)程啟動

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    深度無多配置一些經(jīng)驗(yàn)心得

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

    Linux守護(hù)進(jìn)程

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

    【Linux學(xué)習(xí)雜談】之守護(hù)進(jìn)程以及簡單創(chuàng)建

    首先我們需要了解一下什么叫做守護(hù)進(jìn)程,以及我們?yōu)槭裁葱枰@樣的進(jìn)程。我們知道當(dāng)我們寫一個簡單的程序的時候我們知道,這個程序比如說printf
    發(fā)表于 09-27 13:28

    升級程序作為一個單獨(dú)進(jìn)程的方法

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

    Xtensa調(diào)試器守護(hù)進(jìn)程在Linux中不工作的原因?怎么解決?

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

    iny Linux有沒有辦法設(shè)置ssh或telnet守護(hù)進(jìn)程可以在啟動后自動執(zhí)行?

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

    守護(hù)進(jìn)程的初級教程

    守護(hù)進(jìn)程的初級教程,淺顯易懂,適合初學(xué)者
    發(fā)表于 06-17 16:16 ?0次下載

    Linux守護(hù)進(jìn)程詳解

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

    linux守護(hù)進(jìn)程實(shí)例

      今天完成一個守護(hù)進(jìn)程實(shí)驗(yàn)?! ? 熟悉守護(hù)進(jìn)程編寫和調(diào)試(系統(tǒng)日志)  2 編寫多進(jìn)程
    發(fā)表于 04-02 14:42 ?399次閱讀

    U啟動盤制作工具應(yīng)用程序免費(fèi)下載

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

    Linux 安全模塊:守護(hù)進(jìn)程和套接字

    守護(hù)進(jìn)程通常是在后臺觀察操作以等待狀態(tài)、服務(wù)于特定子系統(tǒng)并確定整個系統(tǒng)的操作規(guī)則的實(shí)用程序。例如,一個守護(hù)進(jìn)程被配置為監(jiān)控打印服務(wù)的狀態(tài)。
    發(fā)表于 08-26 10:01 ?670次閱讀

    Rust -- rust連接oss

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

    Rust -- tokio綁定cpu實(shí)踐

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

    程序進(jìn)程和線程的區(qū)別

    什么是進(jìn)程 1、進(jìn)程和線程的區(qū)別 進(jìn)程是指正在運(yùn)行的程序,它擁有獨(dú)立的內(nèi)存空間和系統(tǒng)資源,不同進(jìn)程之間的數(shù)據(jù)不共享。
    的頭像 發(fā)表于 06-22 11:39 ?664次閱讀
    <b class='flag-5'>程序</b>中<b class='flag-5'>進(jìn)程</b>和線程的區(qū)別

    Linux中如何編寫守護(hù)進(jìn)程程序

    的一種進(jìn)程,它們一般在系統(tǒng)啟動時開始運(yùn)行,除非強(qiáng)行終止,否則直到系統(tǒng)關(guān)機(jī)都會保持運(yùn)行。與守護(hù)進(jìn)程相比,普通進(jìn)程都是在用戶登錄或運(yùn)行
    的頭像 發(fā)表于 10-07 17:12 ?639次閱讀
    Linux中如何編寫<b class='flag-5'>守護(hù)</b><b class='flag-5'>進(jìn)程</b><b class='flag-5'>程序</b>
    RM新时代网站-首页