golang - 如何使用signal,break一个有阻塞监听的for循环?

查看:399
本文介绍了golang - 如何使用signal,break一个有阻塞监听的for循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

func Soo(){
    tcpAddr, _ := net.ResolveTCPAddr("tcp", ipaddr)
    tcpListener, _ := net.ListenTCP("tcp", tcpAddr)
    for {
        tcpConn, err := tcpListener.AcceptTCP()
        if err != nil {
            fmt.Println("accept error: ", err)
        }
        defer tcpConn.Close()

        go Dotings(tcpConn)
    }
}

因为代码会在 tcpListener.AcceptTCP()处阻塞监听,想使用signal实现键盘Ctrl+C,break出for循环。该如何实现?

解决方案

简单一点的办法就是新开一个线程去Accept, 收到Signal之后Close掉Listener, 然后这个时候Accept会立即返回一个Erroruse of closed network connection. 代码大概长这样:

func server(stopSignal chan int) {
    l, _ := net.Listen("tcp", ":8888")
    cr := make(chan net.Conn)
    go func(l net.Listener, cr chan net.Conn) {
        for {
            conn, err := l.Accept()
            if err != nil {
                log.Printf("accept error: %s", err)
                l.Close()
                break
            }
            cr <- conn
        }
    }(l, cr)
LOOP_ACCEPT:
    for {
        select {
        case conn := <-cr:
            // 这里可以做其它事情, 比如通过channel转出去或者直接开线程处理什么的
            log.Printf("new connection, from: %s", conn.RemoteAddr().String())
            conn.Close()
        case <-stopSignal:
            l.Close()
            break LOOP_ACCEPT
        }
    }
}

调用的时候传入一个参数stopSignal, 当收到这个signal的时候会立即停止Accept. 测试可以这样写:

func main() {
    sig := make(chan int)
    go server(sig)
    time.Sleep(time.Second * 4)
    sig <- 1
    time.Sleep(time.Second * 2)
}

如果要换种方式, 估计就得用syscall拿到原始的fd再调用syscall.SetNonblock设置成非阻塞模式了.

这篇关于golang - 如何使用signal,break一个有阻塞监听的for循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆