golang中的信号处理与网络编程

时间:2018-04-18 19:02:42

标签: go networking

尝试学习golang网络编程。实施简单 带有unix域套接字的服务器。服务器有:

  1. taskChan:客户端连接对象的Unbuf通道。
  2. sigChan:buf channel for signals
  3. srvDone:unbuf channel表示服务器已完成。
  4. 阻止除SIGINT / SIGHUP之外的所有异步信号。
  5. 然后启动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()
    }
    

0 个答案:

没有答案