刚学 golang ,最近在写一个代理服务器.使用了自带的 net 库来需要实现数据的中转。
服务器有这样一个逻辑:当收到目标服务器的数据时,需要转发给客户端。
但是查了一下资料,net.Conn.Read 方法可以读取来自目标服务器的数据,但是每次都需要手动调用,
我也不想写死循环或者 time.Sleep 之类的轮询。
自带的 net 库虽然底层是多路复用的封装, 但是没有暴露像 netty 一样的事件回调,也没有 java NIO 的可读事件通知,请问该怎么处理这种情况呢?需要依赖第三方包或者自己底层重新写一套? 求各位大佬指教。 [哭]
1
icexin 2019-10-29 17:54:25 +08:00 1
Read 是阻塞调用,没有数据不会返回的。
|
2
wdmx007 OP @icexin 对啊,但是我需要在有可读数据的第一时间转发到客户端,轮询调用 Read 是可以解决的,但是太难看了。请问有其他办法吗?
|
3
misaka19000 2019-10-29 18:00:56 +08:00
自己写个回调不就行了
|
6
wdmx007 OP @misaka19000 请问在哪里注册回调呢? 大概找了一下,不知道找哪里设置。net.Conn 接口没看到回调注册啊。
|
7
wdmx007 OP @icexin 谢谢,刚学 go,对这个不太熟。如果没有数据调用 Read 会阻塞等待的话,直接找协程里面写死循环就可以了。我去试试。
|
8
misaka19000 2019-10-29 18:07:19 +08:00 1
每个连接开一个协程,之后
callback = function (data) { } for { data = net.Read() callback(data) } 搞定,这就是回调 |
9
ScepterZ 2019-10-29 18:17:21 +08:00
按理说阻塞不是比回调好理解多了么……这就是 go 的卖点啊
|
10
wdmx007 OP @ScepterZ 主要是我理解错了,以为没数据的时候 read 会直接返回,所以我就以为需要不停的调用查看是否有数据。实际上如果是阻塞到有数据来了才返回的话,就很好理解了。
|
11
reus 2019-10-29 18:42:08 +08:00 1
可以实现啊,自己调 epoll 就行
不过看你回复,原来不知道 Read 是阻塞调用,那可以认为你不懂基本的网络读写了,更不用说 epoll 能力不够的时候,“不想写”,“太难看“这种话,是没有资格说的 |
12
whoami9894 2019-10-29 18:44:48 +08:00 via Android
syscall.SetNonblock 然后 select 轮询?不知道 go 的范式是不是这样做
|
13
wdmx007 OP @reus 谢谢回复。因为没认真研究过 socket,只写过 java nio,epoll 还是知道的,不然我也不会说什么可读事件通知这种话了😂
|
14
zunceng 2019-10-29 19:32:14 +08:00 1
严重怀疑楼上几位是不是写过 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 |
16
zunceng 2019-10-29 19:47:50 +08:00 1
@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 } |
17
zunceng 2019-10-29 19:49:35 +08:00
抱歉 语法错+错误处理有问题 意思到了吧
|
18
useben 2019-10-29 20:24:52 +08:00
人家就是把异步封装成同步的写法给你,你还要去找异步的。。。
|