Golang Go语言中 net 包读取数据问题,如何触发 Conn 的可读事件

发布于 1周前 作者 ionicwang 来自 Go语言

Golang Go语言中 net 包读取数据问题,如何触发 Conn 的可读事件

刚学 golang ,最近在写一个代理服务器.使用了自带的 net 库来需要实现数据的中转。
服务器有这样一个逻辑:当收到目标服务器的数据时,需要转发给客户端。
但是查了一下资料,net.Conn.Read 方法可以读取来自目标服务器的数据,但是每次都需要手动调用, 我也不想写死循环或者 time.Sleep 之类的轮询。

自带的 net 库虽然底层是多路复用的封装, 但是没有暴露像 netty 一样的事件回调,也没有 java NIO 的可读事件通知,请问该怎么处理这种情况呢?需要依赖第三方包或者自己底层重新写一套? 求各位大佬指教。 [哭]


更多关于Golang Go语言中 net 包读取数据问题,如何触发 Conn 的可读事件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

19 回复

Read 是阻塞调用,没有数据不会返回的。

更多关于Golang Go语言中 net 包读取数据问题,如何触发 Conn 的可读事件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


对啊,但是我需要在有可读数据的第一时间转发到客户端,轮询调用 Read 是可以解决的,但是太难看了。请问有其他办法吗?

自己写个回调不就行了

就用 go 轮询

有数据 Read 就立马返回,你再转发,没有数据就阻塞等待,有什么问题吗?

请问在哪里注册回调呢? 大概找了一下,不知道找哪里设置。net.Conn 接口没看到回调注册啊。

谢谢,刚学 go,对这个不太熟。如果没有数据调用 Read 会阻塞等待的话,直接找协程里面写死循环就可以了。我去试试。

每个连接开一个协程,之后

callback = function (data) {

}

for {
data = net.Read()
callback(data)
}

搞定,这就是回调

按理说阻塞不是比回调好理解多了么……这就是 go 的卖点啊

主要是我理解错了,以为没数据的时候 read 会直接返回,所以我就以为需要不停的调用查看是否有数据。实际上如果是阻塞到有数据来了才返回的话,就很好理解了。

可以实现啊,自己调 epoll 就行

不过看你回复,原来不知道 Read 是阻塞调用,那可以认为你不懂基本的网络读写了,更不用说 epoll

能力不够的时候,“不想写”,“太难看“这种话,是没有资格说的

syscall.SetNonblock 然后 select 轮询?不知道 go 的范式是不是这样做

谢谢回复。因为没认真研究过 socket,只写过 java nio,epoll 还是知道的,不然我也不会说什么可读事件通知这种话了😂

严重怀疑楼上几位是不是写过 Golang

golang 里面的 tcp proxy 基本上就是 go 两个函数 各自把一个 socket 读通道的数据写到另一个 scoket 的写通道上

参考
https://github.com/kahlys/proxy/blob/master/proxy.go#L74
https://github.com/google/tcpproxy/blob/master/tcpproxy.go#L353

我需要把目标服务器数据进行加密后转发的。不过本质的思路确实如你所说。

你先实现一个加解密的 pipe ( reader + writer )

把 proxy 上在 io.Copy 替换成这个 pipe 就可以了

func proxy ( src. dst net.Conn ) error {
errCh := make(chan error, 1)

go func () {
errCh<- io.Copy(src, dst) // TODO: replace with your pipe
}

go func () {
errCh<- io.Copy(dst, src) // TODO: replace with your pipe
}

return <-errCh
}

抱歉 语法错+错误处理有问题 意思到了吧

人家就是把异步封装成同步的写法给你,你还要去找异步的。。。

在Go语言中,net包提供了对网络编程的支持,包括TCP、UDP等协议。对于net.Conn接口的可读事件,Go语言并没有像某些其他编程语言(如C语言的select系统调用或Python的selectors模块)那样直接提供可读事件的回调机制。相反,Go语言通常使用goroutine和channel来实现非阻塞的I/O操作。

要触发并处理net.Conn的可读事件,你可以采取以下步骤:

  1. 启动一个goroutine来读取数据。在这个goroutine中,你可以使用conn.Read方法读取数据。这个方法会阻塞,直到有数据可读或者连接关闭。

  2. 使用channel来通知其他goroutine数据已经读取完毕或者发生了错误。这样,你就可以在需要处理数据的地方等待这个channel的信号,而不是直接阻塞在Read方法上。

  3. 错误处理:在读取数据时,要检查是否发生了错误(如连接被对方关闭)。如果发生错误,你可以关闭这个连接,并通过channel通知其他goroutine进行相应的处理。

  4. 超时处理:如果你需要设置读取超时,可以使用conn.SetReadDeadline方法。这样,如果读取操作在指定的时间内没有完成,Read方法会返回一个超时错误。

通过上述方法,你可以有效地处理net.Conn的可读事件,并在Go语言的并发模型中优雅地管理网络I/O。

回到顶部