Go 言語は高速かつ効率的なプログラミング言語であり、組み込みの同時実行サポート、軽量スレッド、ガベージ コレクション メカニズムなど、デーモン プロセス開発に優れた機能を備えています。デーモンはバックグラウンドで実行できるプログラムであり、通常は長時間実行する必要があり、ネットワーク接続要求などの外部イベントを常にリッスンし、それに応じて発生したイベントを処理します。この記事ではGo言語でデーモンプロセスを開発する方法を紹介します。
1. デーモン プロセスの基本要件
Linux および Unix オペレーティング システムでは、デーモン プロセスはいくつかの基本要件を満たす必要があります:
- 親プロセスが必要, この親プロセスは、システムの再起動後もデーモンが確実に実行できるようにする init プロセスであることが望ましいです。
- デーモンは、起動時に自身をバックグラウンドに置き、制御端末を解放する必要があります。
- デーモンは、システムのシャットダウンまたは終了時にデーモン自体を適切にクリーンアップするために、SIGTERM や SIGINT などのシグナルを処理できる必要があります。
2. デーモン プロセスを実装する手順
Go 言語でデーモン プロセスを開発するには、次の手順を完了する必要があります。子プロセスを実行し、親プロセスを終了します。 プロセス;
setsid() 関数を呼び出して新しいセッション グループを作成し、現在のプロセスをセッション グループのリーダーおよび新しいプロセス グループの唯一のメンバーにします; - ファイル記述子 0、1、2 (標準入力、標準出力、標準エラー出力) を閉じる;
- ファイル システムのルート ディレクトリ (/) の下に書き込み可能なディレクトリを作成し、そのファイル記述子を開きます、それをプロセスの作業ディレクトリとルート ファイル システムとして使用します;
- プログラムの開始時に必要なリソース (構成ファイル、環境変数などを含む) をロードします;
- プロセス SIGTERMおよび SIGINT シグナルは、プログラムのリソースを正しくクリーンアップします。
-
- 以下では、これらの手順の具体的な実装を 1 つずつ紹介します。
3. 実装の詳細
子プロセスの作成と親プロセスの終了
- 子プロセスの作成と親プロセスの終了のためのコード スニペットGo 言語では次のようになります。
func startDaemon() {
cmd := exec.Command(os.Args[0])
cmd.Start()
os.Exit(0)
}
ログイン後にコピー
このコードは、新しいプロセスを開始し、現在のプロセスを終了し、新しいプロセスをデーモン プロセスの子プロセスにします。
新しい会話グループの作成
- Go 言語で新しい会話グループを作成するコード スニペットは次のとおりです:
func startDaemon() {
syscall.Umask(0)
if syscall.Getppid() == 1 {
return
}
cmd := exec.Command(os.Args[0])
cmd.Start()
os.Exit(0)
...
sysret, syserr := syscall.Setsid()
if syserr != nil || sysret < 0 {
fmt.Fprintf(os.Stderr, "Error: syscall.Setsid errno:%d %v
", syserr, syserr)
os.Exit(1)
}
}
ログイン後にコピー
このコードは最初に設定します。ファイルをアップします。 許可マスクは 0 で、現在のプロセスがすでにセッション グループのリーダー プロセスであるかどうか (つまり、親プロセスが初期プロセスであるかどうか) を確認します。その場合、新しい会話グループを作成する必要はありません。それ以外の場合は、前述の setsid() 関数を呼び出して新しいセッション グループを作成し、現在のプロセスをセッション グループのリーダーにします。
ファイル記述子を閉じる
- Go 言語では、ファイル記述子を閉じるためのコード部分は次のとおりです。
func startDaemon() {
syscall.Umask(0)
if syscall.Getppid() == 1 {
return
}
cmd := exec.Command(os.Args[0])
cmd.Start()
os.Exit(0)
...
syscall.Close(0) // close stdin
syscall.Close(1) // close stdout
syscall.Close(2) // close stderr
}
ログイン後にコピー
このコードでは、 syscall パッケージ Close() 関数は、ファイル記述子 0、1、および 2 を閉じます。
書き込み可能なディレクトリを作成する
- Go 言語で書き込み可能なディレクトリを作成するコード スニペットは次のとおりです。
func startDaemon() {
syscall.Umask(0)
if syscall.Getppid() == 1 {
return
}
cmd := exec.Command(os.Args[0])
cmd.Start()
os.Exit(0)
...
os.Chdir("/")
dir, _ := ioutil.TempDir("", "")
fd, _ := os.Open(dir)
syscall.Dup2(int(fd.Fd()), 0)
syscall.Dup2(int(fd.Fd()), 1)
syscall.Dup2(int(fd.Fd()), 2)
}
ログイン後にコピー
このコードは、最初にプロセスを削除します。現在の作業ディレクトリをルート ディレクトリ (/) に変更し、ioutil パッケージの TempDir() 関数を使用して、/tmp ディレクトリの下に新しいディレクトリを作成します。次に、os.Open() 関数を使用してディレクトリを開き、syscall パッケージの Dup2() 関数を使用してそのファイル記述子を標準入力、標準出力、および標準エラーのファイル記述子にコピーします。
必要なリソースをロードする
- 必要なリソースをロードするためのコード部分は、プログラムのエントリ関数に記述できます。
SIGTERM および SIGINT シグナルの処理
- Go 言語で SIGTERM および SIGINT シグナルを処理するコードは次のとおりです。
func main() {
...
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
// 执行清理操作
os.Exit(0)
}()
...
}
ログイン後にコピー
このコードは OS を使用します。パッケージ Signal() 関数は、SIGTERM および SIGINT シグナルを処理のためにパイプラインに転送します。次に、別のゴルーチンでこのパイプをリッスンすることで、これらのシグナルを受信したときにクリーンアップ操作を実行できます。
4. 概要
この記事では、Go 言語でデーモン プロセスを開発する方法を紹介します。デーモンは、さまざまな外部イベントを処理する必要がある長時間実行されるプログラムであり、親プロセスを持つこと、起動時に自身をバックグラウンドに置くことなど、いくつかの基本的な要件を満たす必要があります。 Go 言語でこれらの要件を実装する方法には、子プロセスの作成と親プロセスの終了、新しいセッション グループの作成、ファイル記述子を閉じる、書き込み可能なディレクトリの作成、必要なリソースのロード、SIGTERM および SIGINT シグナルの処理などが含まれます。これらの方法をマスターすれば、Go言語で自由にデーモンプロセスを開発できるようになります。
以上がGo言語でデーモンプロセスを開発するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。