V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
proxytoworld
V2EX  ›  问与答

解决 golang 的无缓冲通道会阻塞的问题

  •  
  •   proxytoworld · 2021-05-03 17:10:29 +08:00 · 960 次点击
    这是一个创建于 1304 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,我需要在建立 TCP 连接之后循环处理来自客户端的连接请求,并接收来自客户端的数据,在客户端第三次发送数据之后断开连接,取消监听,我使用 select 来取消无缓冲通道的阻塞,但是 handleTcpConnection 向通道发送信号后,sendAndReceiveTcpData 没办法接收信号,导致程序卡死在 handleTcpConnection

    如果不用 select 则程序会阻塞在 sendAndReceiveTcpData 接收通道的代码处,没办法处理第二个用户请求,求问怎么解决该问题

    func sendAndReceiveTcpData(ln net.Listener) {
    defer func() {
    	helper.Wt.Done()
    	log.Println("sendAndReceiveTcpData 返回")
    }()
    exitSignal := make(chan bool)
    log.Println("信号创建")
    var clientNumber = 1
    for {
    	log.Printf("等待第%d 客户端请求\n", clientNumber)
    	conn, err := ln.Accept()
    	log.Println("接到请求")
    	if err != nil {
    		log.Fatalf("和客户端连接失败%s\n", err)
    	}
    	log.Println("和客户端连接成功")
    	clientNumber++
    	helper.Wt.Add(1)
    	go handleTcpConnection(conn, &exitSignal)
    
    	log.Println("handleTcpConnection 协程创建")
    	select {
    	case <-exitSignal:
    		e := <-exitSignal
    		log.Println("接到信号")
    		if e{
    			goto x
    		}
    	default:
    		log.Println("下一轮")
    	}
    }
    x:
    	log.Println("结束 senddata for 循环")
    }
    func handleTcpConnection(conn net.Conn, e *chan bool) bool {
        defer func() {
            helper.Wt.Done()
            log.Print("handleTcpConnection 返回\n")
    
        }()
    
        br := bufio.NewReader(conn)
        var counter = 0
        for {
            data, err := br.ReadString('\n')
            if err == io.EOF {
                break
            }
            if counter == 3{
                log.Println("发送信号")
                *e<-true
                break
            }
            log.Printf("客户端 %s => %s", conn.RemoteAddr(), data)
            counter++
        }
        log.Println("结束 handle for 循环")
        return true
    }
    
    5 条回复    2021-05-03 21:47:04 +08:00
    pabupa
        1
    pabupa  
       2021-05-03 17:46:07 +08:00
    因为`ln.Accept()`是阻塞调用。它会卡到有新连接来的时候才返回。
    proxytoworld
        2
    proxytoworld  
    OP
       2021-05-03 17:58:28 +08:00
    @pabupa 刚刚注意到了这个问题,如何解决这种问题?一边等待新的连接,一边监听已有的连接是否发出信号
    proxytoworld
        3
    proxytoworld  
    OP
       2021-05-03 17:59:39 +08:00
    同时有两个阻塞调用
    AlisaDestiny
        4
    AlisaDestiny  
       2021-05-03 18:23:56 +08:00
    专门起一个 goroutine 监听 exitSignal,接收到信号就调用 Listener 的 Close 方法。
    proxytoworld
        5
    proxytoworld  
    OP
       2021-05-03 21:47:04 +08:00
    @AlisaDestiny 有道理
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6020 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 02:06 · PVG 10:06 · LAX 18:06 · JFK 21:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.