V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
wdmx007
V2EX  ›  Go 编程语言

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

  •  
  •   wdmx007 · 2019-10-29 17:51:04 +08:00 · 4386 次点击
    这是一个创建于 1863 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    callback = function (data) {

    }

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

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

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

    能力不够的时候,“不想写”,“太难看“这种话,是没有资格说的
    whoami9894
        12
    whoami9894  
       2019-10-29 18:44:48 +08:00 via Android
    syscall.SetNonblock 然后 select 轮询?不知道 go 的范式是不是这样做
    wdmx007
        13
    wdmx007  
    OP
       2019-10-29 19:13:44 +08:00 via Android
    @reus 谢谢回复。因为没认真研究过 socket,只写过 java nio,epoll 还是知道的,不然我也不会说什么可读事件通知这种话了😂
    zunceng
        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
    wdmx007
        15
    wdmx007  
    OP
       2019-10-29 19:38:01 +08:00 via Android
    @zunceng 我需要把目标服务器数据进行加密后转发的。不过本质的思路确实如你所说。
    zunceng
        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
    }
    zunceng
        17
    zunceng  
       2019-10-29 19:49:35 +08:00
    抱歉 语法错+错误处理有问题 意思到了吧
    useben
        18
    useben  
       2019-10-29 20:24:52 +08:00
    人家就是把异步封装成同步的写法给你,你还要去找异步的。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6004 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 02:11 · PVG 10:11 · LAX 18:11 · JFK 21:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.