我正在学习Go和ZeroMQ,并且本着这种精神,我正在尝试为Zguide贡献Go示例。我和interrupt example有点挣扎。我不确定处理问题的惯用方法是什么。
我目前的解决方案如下:我创建一个接收SIGINT信号的通道。当它这样做时,我在另一个通道上写一个bool,它在主循环中用来打破。问题是,Recv是阻塞的,循环永远不会检查循环条件。我通过将NOBLOCK常量传递给Recv来避免这个问题。但是我觉得有一种更好的方法,因为Recv应该在中断时返回一个EINTR(它没有我能说的那么多)。你的读者能够更好地回答这个问题然后我,你觉得怎么样?
为了您的方便,我到目前为止的代码:
package main
import (
"os/signal"
"os"
"fmt"
zmq "github.com/alecthomas/gozmq"
)
func listenForSignals(exit_channel chan bool) {
signal_channel := make(chan os.Signal)
signal.Notify(signal_channel)
<- signal_channel
fmt.Println("stopping")
exit_channel <- true
}
func main() {
exit := make(chan bool)
exit_signal := false
go listenForSignals(exit)
context, _ := zmq.NewContext()
defer context.Close()
socket, _ := context.NewSocket(zmq.REP)
defer socket.Close()
socket.Bind("tcp://*:5555")
for exit_signal == false {
select {
case exit_signal = <- exit:
fmt.Println("W: interrupt received, killing server...")
default:
msgbytes, err := socket.Recv(zmq.NOBLOCK)
fmt.Printf("%s.\n", string(msgbytes))
}
}
}
编辑根据反馈稍微简化了代码
答案 0 :(得分:2)
如果要使用select语句切换通道,则还应在通道上返回socket.Recv的结果。这也允许你在goroutine上运行socket.Recv,因此阻塞性质不是问题。
实际上,你应该也可以处理你得到的错误。你可以通过向整个shebang添加另一个频道来做。
func main() {
...
data := make(chan []byte)
errors := make(chan error)
go function() {
for {
msgbytes, err := socket.Recv(0)
if err != nil {
errors <- err
} else {
data <- msgbytes
}
}
}()
for exit_signal == false {
select {
case exit_signal = <- exit:
fmt.Println("W: interrupt received, killing server...")
case err := <- errors:
fmt.Println("Receive Error:", err.Error())
case msgbytes := <- data:
fmt.Printf("%s.\n", string(msgbytes))
}
}
}
答案 1 :(得分:0)
这看起来有点过于复杂。在主体中,您可以启动goroutine等待中断信号:
go func() {
sigchan := make(chan os.Signal, 10)
signal.Notify(sigchan, os.Interrupt)
<-sigchan
log.Println("Application killed !")
// do things like writing your last will or cursing the killer before you really die
os.Exit(2)
}()
// starts the things your application has to do