[GO] net 包读取数据问题,如何触发 Conn 的可读事件

2019-10-29 17:51:04 +08:00
 wdmx007

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

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

4402 次点击
所在节点    Go 编程语言
18 条回复
icexin
2019-10-29 17:54:25 +08:00
Read 是阻塞调用,没有数据不会返回的。
wdmx007
2019-10-29 17:57:06 +08:00
@icexin 对啊,但是我需要在有可读数据的第一时间转发到客户端,轮询调用 Read 是可以解决的,但是太难看了。请问有其他办法吗?
misaka19000
2019-10-29 18:00:56 +08:00
自己写个回调不就行了
1314258
2019-10-29 18:01:23 +08:00
@wdmx007 就用 go 轮询
icexin
2019-10-29 18:03:58 +08:00
@wdmx007 有数据 Read 就立马返回,你再转发,没有数据就阻塞等待,有什么问题吗?
wdmx007
2019-10-29 18:04:11 +08:00
@misaka19000 请问在哪里注册回调呢? 大概找了一下,不知道找哪里设置。net.Conn 接口没看到回调注册啊。
wdmx007
2019-10-29 18:06:53 +08:00
@icexin 谢谢,刚学 go,对这个不太熟。如果没有数据调用 Read 会阻塞等待的话,直接找协程里面写死循环就可以了。我去试试。
misaka19000
2019-10-29 18:07:19 +08:00
每个连接开一个协程,之后

callback = function (data) {

}

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

搞定,这就是回调
ScepterZ
2019-10-29 18:17:21 +08:00
按理说阻塞不是比回调好理解多了么……这就是 go 的卖点啊
wdmx007
2019-10-29 18:31:11 +08:00
@ScepterZ 主要是我理解错了,以为没数据的时候 read 会直接返回,所以我就以为需要不停的调用查看是否有数据。实际上如果是阻塞到有数据来了才返回的话,就很好理解了。
reus
2019-10-29 18:42:08 +08:00
可以实现啊,自己调 epoll 就行

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

能力不够的时候,“不想写”,“太难看“这种话,是没有资格说的
whoami9894
2019-10-29 18:44:48 +08:00
syscall.SetNonblock 然后 select 轮询?不知道 go 的范式是不是这样做
wdmx007
2019-10-29 19:13:44 +08:00
@reus 谢谢回复。因为没认真研究过 socket,只写过 java nio,epoll 还是知道的,不然我也不会说什么可读事件通知这种话了😂
zunceng
2019-10-29 19:32:14 +08:00
严重怀疑楼上几位是不是写过 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
wdmx007
2019-10-29 19:38:01 +08:00
@zunceng 我需要把目标服务器数据进行加密后转发的。不过本质的思路确实如你所说。
zunceng
2019-10-29 19:47:50 +08:00
@wdmx007 你先实现一个加解密的 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
}
zunceng
2019-10-29 19:49:35 +08:00
抱歉 语法错+错误处理有问题 意思到了吧
useben
2019-10-29 20:24:52 +08:00
人家就是把异步封装成同步的写法给你,你还要去找异步的。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/614153

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX