简体   繁体   中英

How to properly control a listener in golang

I want to control a listener depending on the state of something, let's say my program will listen if the content of a file is 1 and don't listen if the content is 0.

The problem is that there's not way, once a listener is initialized, to tell him to refuse connection. There is only the 'accept' state; I have to close the listener.

So I found a way to do it using the following code, but I feel that's not a good way to do because i'm using a global and usually it's not a good idea.

Is there a better way to do it?

var healthStatus bool

func listen(l net.Listener, port int) {
    var err error
    l, err = net.Listen("tcp", ":"+strconv.Itoa(port))
    if err != nil {
        panic(err)
    }

    defer l.Close()
    for {
        if healthStatus == false {
            _ = l.Close()
            return
        }
        logrus.Debug("Going to listen !")
        conn, err := l.Accept()
        if err != nil {
            panic(err)
        }
        go func(c net.Conn) {
            _ = c.Close()
        }(conn)
        }
    }


func main() {
    healthStatus = true

    var listener net.Listener
    var isListening = false

    for {
        logrus.Debug("Performing checks...")
        healthStatus = healthcheck()
        

        if healthStatus {
            if !isListening {
                isListening = true
                //Restart listener
                go listen(listener, config.port)
            }
        }

        if !healthStatus {
            if isListening {
                isListening = false
            }
        }

        time.Sleep(time.Second * 10)
    }
}

EDIT: With channel

package main

import (
    "net"
    "strconv"
    "time"
)

var listening = make(chan bool)

func listen(l net.Listener, port int) {
    var err error
    l, err = net.Listen("tcp", ":"+strconv.Itoa(port))
    if err != nil {
        panic(err)
    }

    defer l.Close()
    for {
        localstatus := <- listening
        if localstatus == false {
        _ = l.Close()
        return
    }
    conn, _ := l.Accept()

    go func(c net.Conn) {
    // Shut down the connection.
        _ = c.Close()
        listening <- true
    }(conn)
    }
    }


func main() {
    healthStatus := true

    var listener net.Listener
    var isListening = false

    for {
        healthStatus = healthcheck()
        

        if healthStatus {
            if !isListening {
                isListening = true
                //Restart listener
                go listen(listener, config.port)
            }
            listening <- true
        }

        if !healthStatus {
            if isListening {
                isListening = false
                listening <- false
            }
        }

        time.Sleep(time.Second * 10)
    }
}

Close the listener when the health goes bad. Use a channel to signal the accept loop that it's a clean shutdown.

var listener net.Listener
var done chan struct{}
for {
    if healthcheck() {
        if listener == nil {
            var err error
            listener, err = net.Listen("tcp", ":"+strconv.Itoa(conig.port))
            if err != nil {
                panic(err)
            }
            done = make(chan struct{})
            go accept(listener, done)
        }
    } else {
        if listener != nil {
            close(done)
            listener.Close()
            done = nil
            listener = nil
        }
    }
    time.Sleep(time.Second * 10)
}

The accept function is:

func accept(l net.Listener, done chan struct{}) {
    for {
        conn, err := l.Accept()
        select {
        case <-done:
            return
        default:
        }
        if err != nil {
            panic(err)
        }
        go func(c net.Conn) {
            _ = c.Close()
        }(conn)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM