V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
recall704
V2EX  ›  问与答

请教一个 golang 的问题: 如何返回第一个连接

  •  
  •   recall704 · 2018-01-01 02:15:29 +08:00 · 1295 次点击
    这是一个创建于 2308 天前的主题,其中的信息可能已经有所发展或是发生改变。

    详细问题是这样的: 我有两个一样的站点,分别为

    1. site1 := "www.aaa.com:80"
    2. site2 := "www.bbb.com:80"

    一般创建一个连接是这样的:

    conn, err := net.Dial("tcp", site1)
    

    我想从站点获取数据,创建连接的时候,我想同时创建,但是谁先创建成功我就要谁。 就像我急着用某件物品,附近有两家超市,我安排两个人同时去买,买到了就行,而不用管是谁买到的。

    func getBestConn()(net.Conn) {
        ch := make(net.Conn, 1)
        site1 := "www.aaa.com:80"
        site2 := "www.bbb.com:80"
        
        go func(){
            cc, err := net.Dial("tcp", site1)
            ch <- cc
        }()
        go func(){
            cc, err := net.Dial("tcp", site2)
            ch <- cc
        }()
        
        return <-cc
    }
    

    我写了上面的代码,但是它不能正常工作。 请问我该怎么做?

    btw, 新年快乐

    第 1 条附言  ·  2018-01-01 13:01:56 +08:00
    func getBestConn(addr1, addr2 string) (net.Conn, error) {
    	ch1 := make(chan net.Conn)
    	ch2 := make(chan net.Conn)
    
    	go func() {
    		cc, err := net.Dial("tcp", addr1)
    		if err != nil {
    			log.Logf("local connect: %s, %v", addr1, err)
    		}
    		ch1 <- cc
    	}()
    
    	go func() {
    		cc, err := net.Dial("tcp", addr2)
    		if err != nil {
    			log.Logf("local connect: %s, %v", addr2, err)
    		}
    		ch2 <- cc
    	}()
    
    	select {
    	case c := <-ch1:
    		// log.Logf("get ch1, %s - %s", c.LocalAddr(), c.RemoteAddr())
    		log.Logf("get ch1")
    		return c, nil
    	case c := <-ch2:
    		// log.Logf("get ch2, %s - %s", c.LocalAddr(), c.RemoteAddr())
    		log.Logf("get ch2")
    		return c, nil
    	case <-time.After(time.Second * 5):
    		log.Logf("timeout")
    		return nil, errors.New("timeout")
    	}
    }
    

    我似乎发现了一个问题,就是两个 conn 都可能成功,而返回之后我只能 close 一个。
    这可如何是好。

    4 条回复    2018-01-01 13:48:01 +08:00
    mlkr
        1
    mlkr  
       2018-01-01 02:19:49 +08:00 via Android   ❤️ 1
    snail1988
        2
    snail1988  
       2018-01-01 10:42:37 +08:00   ❤️ 1
    你的想法可以实现啊,不过你贴的代码有明显错误

    ```
    func getBestConn()(net.Conn) {
    ch := make(chan net.Conn, 1)
    site1 := "www.baidu.com:80"
    site2 := "www.taobao.com:80"
    go func(){
    cc, _ := net.Dial("tcp", site1)
    ch <- cc
    }()
    go func(){
    cc, _ := net.Dial("tcp", site2)
    ch <- cc
    }()
    return <-ch
    }
    ```
    recall704
        3
    recall704  
    OP
       2018-01-01 12:25:54 +08:00
    @snail1988 手写的,所以。。。
    suconghou
        4
    suconghou  
       2018-01-01 13:48:01 +08:00   ❤️ 1
    无缓冲 chan,入的时候用 select 和 default,后入的会阻塞,走 default close
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1053 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:06 · PVG 03:06 · LAX 12:06 · JFK 15:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.