golang - 如何使用signal,break一个有阻塞监听的for循环?
本文介绍了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屋!
查看全文