Golang捕获信号

huangapple go评论84阅读模式
英文:

Golang catch signals

问题

我想在Go语言中实现一个"进程包装器"。基本上它的功能是启动一个进程(比如一个Node服务器)并监控它(捕获诸如SIGKILL、SIGTERM等信号)。

我认为可以通过在一个Go协程中使用syscall.Exec来启动Node服务器:

func launchCmd(path string, args []string) {
  err := syscall.Exec(path, args, os.Environ())
  if err != nil {
    panic(err)
  }
}

然后,我想捕获syscall执行的命令生成的所有可能的信号。我对Go还不太熟悉,希望能得到帮助。

英文:

I want to implement a "process wrapper" in Go. Basically what it will do, is launch a process (lets say a node server) and monitor it (catch signals like SIGKILL, SIGTERM ...)

I think the way to do is to launch the node server in a go routine using syscall.Exec:

func launchCmd(path string, args []string) {
  err := syscall.Exec(path, args, os.Environ())
  if err != nil {
    panic(err)
  }
}

Then I'd like to catch every possible signals generated by the command executed by syscall. I'm pretty new to Go, any help would be appreciated.

答案1

得分: 71

在Go语言中,有三种执行程序的方式:

  1. 使用syscall包的syscall.Execsyscall.ForkExecsyscall.StartProcess方法。
  2. 使用os包的os.StartProcess方法。
  3. 使用os/exec包的exec.Command方法。

syscall.StartProcess是底层方法,它返回一个uintptr作为句柄。

os.StartProcess方法返回一个方便使用的os.Process结构体,可以调用Signal方法。os/exec包提供了io.ReaderWriter用于在管道上使用。这两种方法内部都使用了syscall

接收来自其他进程的信号似乎有点棘手。如果可能的话,syscall应该能够做到。在更高级的包中,我没有看到明显的方法。

要接收信号,可以使用signal.Notify方法,示例如下:

sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
	syscall.SIGHUP,
	syscall.SIGINT,
	syscall.SIGTERM,
	syscall.SIGQUIT)
go func() {
    s := <-sigc
	// ... 做一些操作 ...
}()

只需更改您感兴趣的信号即可。如果不指定信号,它将捕获所有可捕获的信号。

您可以使用syscall.KillProcess.Signal方法发送信号。可以从Process.Pidsyscall.StartProcess的结果中获取进程ID。

英文:

There are three ways of executing a program in Go:

  1. syscall package with syscall.Exec, syscall.ForkExec, syscall.StartProcess
  2. os package with os.StartProcess
  3. os/exec package with exec.Command

syscall.StartProcess is low level. It returns a uintptr as a handle.

os.StartProcess gives you a nice os.Process struct that you can call Signal on. os/exec gives you io.ReaderWriter to use on a pipe. Both use syscall internally.

Reading signals sent from a process other than your own seems a bit tricky. If it was possible, syscall would be able to do it. I don't see anything obvious in the higher level packages.

To receive a signal you can use signal.Notify like this:

sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
	syscall.SIGHUP,
	syscall.SIGINT,
	syscall.SIGTERM,
	syscall.SIGQUIT)
go func() {
    s := &lt;-sigc
	// ... do something ...
}()

You just need to change the signals you're interested in listening to. If you don't specify a signal, it'll catch all the signals that can be captured.

You would use syscall.Kill or Process.Signal to map the signal. You can get the pid from Process.Pid or as a result from syscall.StartProcess.

答案2

得分: 39

你可以使用signal.Notify

import (
	"os"
	"os/signal"
	"syscall"
)

func main() {
	signalChannel := make(chan os.Signal, 2)
	signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
	go func() {
		sig := <-signalChannel
		switch sig {
		case os.Interrupt:
			//处理 SIGINT
		case syscall.SIGTERM:
			//处理 SIGTERM
		}
	}()
	// ...
}
英文:

You can use signal.Notify :

import (
&quot;os&quot;
&quot;os/signal&quot;
&quot;syscall&quot;
)

func main() {
	signalChannel := make(chan os.Signal, 2)
	signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
	go func() {
		sig := &lt;-signalChannel
		switch sig {
		case os.Interrupt:
			//handle SIGINT
		case syscall.SIGTERM:
			//handle SIGTERM
		}
	}()
	// ...
}

答案3

得分: 1

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT, syscall.SIGSEGV)
	for {
		s := <-c
		switch s {
		case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
			return
		case syscall.SIGHUP:
		case syscall.SIGSEGV:
		default:
			return
		}
	}
}

这是一个Go语言的代码片段。它创建了一个通道c,并使用signal.Notify函数将一些系统信号(SIGHUP、SIGQUIT、SIGTERM、SIGINT、SIGSEGV)发送到通道c中。然后,通过一个无限循环,从通道c中接收信号s,并根据不同的信号进行处理。如果接收到的信号是SIGQUIT、SIGTERM或SIGINT,程序将返回;如果接收到的信号是SIGHUP或SIGSEGV,程序将继续执行;否则,程序也将返回。

英文:
func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT, syscall.SIGSEGV)
	for {
		s := &lt;-c
		switch s {
		case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
			return
		case syscall.SIGHUP:
		case syscall.SIGSEGV:
		default:
			return
		}
	}
}

huangapple
  • 本文由 发表于 2013年8月7日 22:55:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/18106749.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定