Go编程艺术 - 异步读写网络连接

在Go中,读写channel与读写Conn是的不一样的。一个协程可以通过select监听并读写多个channel, 但却不能类似这样监听并读写多个Conn(除非自行封装epoll)。如果想在一个协程中监听并读写多个channel和Conn, 那更不好办了。一般的方式是使用专门的协程来处理Conn的读写,使其转换为channel,以供主协程多路监听读写。

由于Conn读写都会阻塞协程,一般情况下,需要两个协程。一个用来读,一个用来写。此时一定要处理好读写的错误,要及时地关闭掉Conn,并退出两个协程,释放掉资源。

这里示例一下处理方法:

转化读写Conn为chan的收发

func process(conn net.Conn, reqch chan<- Request, rspch <-chan Response) {
    var wg sync.WaitGroup
    ctx, cancel := context.WithCancel(context.Background())
    
    // 写
    wg.Add(1)
    go func() {
        defer wg.Done()
    
        for {
            select {
            case req := <-reqch:
                _, err := conn.Write(req.Marshal())
                if err != nil {
                    conn.Close()
                    return
                }
              
              	// 处理数据
              	// ...
            }
            
            case <-ctx.Done():
          			// 读协程已关闭conn, 写协程需要立即退出。
                return
        }
    }()
    
    // 读
    go func() {
        defer wg.Done()
        
        rbuf := make([]byte, 1024)
        
        for {
            rlen, err := conn.Read(rbuf)
            if err != nil{
                if err != net.ErrClosed() {
                    conn.Close()
                  
                  	// 及时通知写协程
                    cancel()
                }
                return
            }
            
            rsp := Unmarshal(rbuf[:rlen])
            
            // 处理数据
            // ...
            
            rspch <- rsp
        }
    }()
    
    wg.Wait()
}

需要注意的是context,这个能保证两个协程的协调退出。

关键的点在于,如果不用context, 写协程只有在下次Write的时候才能发现Conn已被关闭,而这个“下次”,不知道是什么时候。

这样就把对Conn的读写转化为了两个chan,主协程只需要两个chan通信。

func processProxy() {
  var conn net.Conn
  var reqch chan Request
  var rspch chan Response
	// ...
  go process(conn, reqch, rspch)
  
	
  select {
    case reqch <- req:
    	// send
    
    case rsp := <-rspch:
    	// recv
    
    default:
    	// ok
  }
  
}

当然,示例程序也不完美。比如,往reqch发送的时候,可以用一个函数封装一下,及时发现chan已满,发送报错。

展开阅读全文

页面更新:2024-05-05

标签:个协   都会   示例   收发   下次   类似   错误   两个   发现   艺术   数据   网络

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top