吴忠躺衫网络科技有限公司

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

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

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

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

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

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

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

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

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

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

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

/src/cmd/cmdserver.rs,構(gòu)建了兩個(gè)啟動(dòng)子命令,分別來調(diào)用 fork 和 daemonize的守護(hù)進(jìn)程啟動(dòng)實(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 啟動(dòng) 通過 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) {
            // 啟動(dòng)子進(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!");
                // 去除后臺(tái)啟動(dòng)參數(shù),避免重復(fù)啟動(dòng)
                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ù)派生出一個(gè)子進(jìn)程;然后解析一下當(dāng)前命令,去掉 -d 參數(shù),構(gòu)建一個(gè)啟動(dòng)命令,子命令啟動(dòng),退出父進(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 會(huì)將工作目錄設(shè)置為 "/",為了避免權(quán)限問題,我們獲取當(dāng)前目錄作為守護(hù)進(jìn)程的工作目錄。不知道是什么原因,在配置了pid_file 后,啟動(dòng)守護(hù)進(jìn)程時(shí)并沒在文件中有記錄 pid。不過也沒關(guān)系,我們可以在外部獲取并記錄守護(hù)進(jìn)程的pid。

兩種方式啟動(dòng)的守護(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ī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3795

    瀏覽量

    81406
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    230

    瀏覽量

    6664

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

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

收藏 人收藏

    評(píng)論

    相關(guān)推薦

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

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

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

    )是不能卸載的,這對(duì)以后的使用會(huì)造成諸多的麻煩(如系統(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)我們寫一個(gè)簡單的程序的時(shí)候我們知道,這個(gè)程序比如說printf
    發(fā)表于 09-27 13:28

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

    步驟:升級(jí)程序作為一個(gè)單獨(dú)的進(jìn)程1. 定時(shí)請(qǐng)求2. 對(duì)比版本號(hào)(使用正則匹配或字符串提取主版本號(hào)、次版本號(hào)、末版本號(hào))3. 當(dāng)前版本號(hào)較小時(shí)下載升級(jí)資源包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)程可以在啟動(dòng)后自動(dòng)執(zhí)行?

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

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

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

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

    較長的進(jìn)程,通常獨(dú)立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。守護(hù)進(jìn)程常常在系統(tǒng)引導(dǎo)載入時(shí)啟動(dòng),在系統(tǒng)關(guān)閉時(shí)終止。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í)例

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

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

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

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

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

    Rust -- rust連接oss

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

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

    )。core_affinity_rs是一個(gè)用于管理CPU親和力的Rust crate。目前支持Linux、Mac OSX和Windows。官方宣稱支持多平臺(tái),本人只做了linux 操作系統(tǒng)的測試。
    的頭像 發(fā)表于 06-11 15:32 ?609次閱讀
    <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 ?730次閱讀
    <b class='flag-5'>程序</b>中<b class='flag-5'>進(jìn)程</b>和線程的區(qū)別

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

    的一種進(jìn)程,它們一般在系統(tǒng)啟動(dòng)時(shí)開始運(yùn)行,除非強(qiáng)行終止,否則直到系統(tǒng)關(guān)機(jī)都會(huì)保持運(yùn)行。與守護(hù)進(jìn)程相比,普通進(jìn)程都是在用戶登錄或運(yùn)行
    的頭像 發(fā)表于 10-07 17:12 ?680次閱讀
    Linux中如何編寫<b class='flag-5'>守護(hù)</b><b class='flag-5'>進(jìn)程</b><b class='flag-5'>程序</b>
    蒙特卡罗网| 百家乐官网游戏发展| 利高百家乐官网现金网| 百家乐官网中的小路怎样| 百家乐技巧心得| 大发888娱乐场客户端| 百家乐官网视频视频| 百家乐官网几点不用补牌| 休闲百家乐的玩法技巧和规则 | 百家乐官网正品| 兰桂坊百家乐的玩法技巧和规则| 迅盈网球比分| 马洪刚百家乐官网技巧| 百家乐有无技巧| 澳门赌场色情| 怎样打百家乐官网的玩法技巧和规则| 百家乐澳门赌| 华宝娱乐城| 阴宅24层手机罗盘| 赌球规则| 澳门百家乐官网国际娱乐城| 百家乐庄闲必胜手段| 888真人赌博| 怎么玩百家乐官网的玩法技巧和规则 | 九州百家乐的玩法技巧和规则 | 百家乐群11889| 银河国际娱乐城| 迷你百家乐官网的玩法技巧和规则 | 塑料百家乐官网筹码| 百家乐游戏技巧| 三江| 百家乐如何视频| 大世界娱乐城真人娱乐| 成人百家乐官网的玩法技巧和规则 | 云鼎百家乐代理| 澳门百家乐官网怎赌才能赚钱 | 做生意必须看风水吗| 百家乐玩法说| 百家乐官网必学技巧| 百家乐真钱斗地主| 娱乐城百家乐官网打不开|