尝试学习golang网络编程。实施简单 带有unix域套接字的服务器。服务器有:
然后启动signalHandler(),三个taskWorker(),acceptClientReqs() 在goroutines。收到信号后(使用kill -SIGINT将信号发送到此进程),信号处理程序设置全局变量 serverShutdown 。我的目的是 - 阅读 serverShutdown 的所有goroutine并彻底退出。但是,有时候所有的工人 线程退出,有时则不然。你看到我的代码中有任何错误吗? 或者我错过了什么?
package main
import "encoding/json"
import "fmt"
import "net"
import "os"
import "os/signal"
import "syscall"
import "time"
var srvShutdown = false
type netServer struct {
listener *net.UnixListener // unix local sock
taskChan chan net.Conn // unbuf channel for client connections
sigChan chan os.Signal // buffered channel
srvDone chan bool
numOfWorkers int
}
// initialize signals.
func initSignals() {
// block all async signals to this server except SIGINT/SIGHUP
signal.Ignore()
}
// initializes server:
// 1) creates listener.
// 2) creates task channel - client connections accepted on this channel.
// 3) initializes few other things such as signal channel, num of workers etc.
func initServer() (*netServer, error) {
sockAddr, err := net.ResolveUnixAddr("unix", "/tmp/unix.socket")
if err != nil {
fmt.Println("initServer() failed on ResolveUnixAddr(): ", err)
return nil, err
}
srvlistener, err := net.ListenUnix("unix", sockAddr)
if err != nil {
fmt.Println("initServer() failed on ListenUnix(): ", err)
return nil, err
}
netSrv := &netServer{
listener: srvlistener,
taskChan: make(chan net.Conn),
sigChan: make(chan os.Signal, 1),
srvDone: make(chan bool),
numOfWorkers: 3,
}
initSignals()
return netSrv, nil
}
// Accept client connections. Each connection is directed onto
// a channel. Worker threads pickup and work on these connections.
func (netSrv *netServer) acceptClientReqs() {
fmt.Println("Listening on /tmp/unix.socket")
for srvShutdown != true {
netSrv.listener.SetDeadline(time.Now().Add(time.Second))
conn, err := netSrv.listener.Accept()
if err != nil {
fmt.Println("Accept failed : ", err)
continue
}
netSrv.taskChan <- conn
}
netSrv.srvDone <- true
fmt.Println("Exiting server")
}
// Pickup a client connection, work on it and close connection.
func (netSrv *netServer) taskWorker(workerId int) {
fmt.Println("taskWorker(): starting worker-", workerId)
// for conn := range netSrv.taskChan {
for srvShutdown != true {
conn := <-netSrv.taskChan
if conn == nil {
fmt.Println("taskWorker(): worker-", workerId, " continue")
continue
}
fmt.Println("taskWorker(): worker-", workerId, " processing client connection: ", conn)
dec := json.NewDecoder(conn)
var Cmd string
dec.Decode(&Cmd)
fmt.Println(" cmd: ", Cmd)
// reply to client
_, err := conn.Write([]byte("AUTH SUCCESS"))
if err != nil {
return
}
conn.Close()
fmt.Println("taskWorker(): worker-", workerId, " processed client connection: ", conn)
}
fmt.Println("taskWorker(): exiting worker-", workerId)
}
// Handle SIGINT and SIGHUP for now.
func (netSrv *netServer) signalHandler() {
signal.Notify(netSrv.sigChan, syscall.SIGINT, syscall.SIGHUP)
sig := <-netSrv.sigChan
fmt.Println("signalHandler() received signal", sig)
srvShutdown = true
}
func (netSrv *netServer) cleanUp() {
close(netSrv.taskChan)
netSrv.listener.Close()
close(netSrv.srvDone)
}
func main() {
srv, err := initServer()
if err != nil {
fmt.Println("initServer() failed - ", err)
return
}
go srv.signalHandler()
for i := 1; i <= srv.numOfWorkers; i++ {
go srv.taskWorker(i)
}
go srv.acceptClientReqs()
// wait server to complete
<-srv.srvDone
srv.cleanUp()
}