[GO] net 包读取数据问题,如何触发 Conn 的可读事件 - V2EX
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 4765 次点击
    这是一个创建于 2181 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚学 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     Solana &nsp;   2592 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 03:22 PVG 11:22 LAX 20:22 JFK 23:22
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86