当前位置:科学 > 正文

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

2023-02-06 19:53:09  来源:黑客与吉他


(资料图片仅供参考)

在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,这个能保证两个协程的协调退出。

写协程写的时候出错,关闭掉Conn,退出;读协程会立即发现Conn已被关掉,退出。读协程读的时候出错,关闭掉Conn,cancel(), 退出。写协程立即发现Conn已被关闭,立即退出。

关键的点在于,如果不用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已满,发送报错。

关键词:

推荐阅读

新石器时代遗址 新石器时代遗址介绍

新石器时代遗址,1965年,英国考古学家卢伯克,首次提出了两个考古术语:旧石器时代和新石器时代。据此,中国史前文化按考古时间分为旧石器 【详细】

菜籽出油率多少?菜籽出油率高不高?

菜籽出油率多少?很多国家都有菜籽,成片的菜籽,美国农场主也不例外。一般来说,榨菜籽的出油率约为32%-36%。有些地区正常达到38%左右,主 【详细】

蓝太阳什么时候出现过 蓝太阳是怎么形成的?

平常晴天的时候都是可以看见太阳的,不过我们也知道平时看到的太阳是黄色的发光发亮的球体,不过今日北京出现蓝太阳,蓝太阳是什么意思?蓝 【详细】

低碳环保节能产业是什么概念 为什么环保受到大家的重视?

低碳环保节能产业,是什么概念,怎么理解?节能环保产业是指为节约能源资源、发展循环经济和保护生态环境提供物质基础和技术支持的产业,是 【详细】

dwg文件是什么 dwg文件用什么打开?

相信很多人都不知道dwg文件用什么打开?,接下来小编就带大家介绍一些方法,大家可以了解一下。一、看图纸参见图纸DwgSeePlus是一个dwg文件 【详细】

关于我们  |  联系方式  |  免责条款  |  招聘信息  |  广告服务  |  帮助中心

联系我们:85 572 98@qq.com备案号:粤ICP备18023326号-40

科技资讯网 版权所有