改进网络代码而不使用goto语句来断开连接情况

时间:2014-10-13 12:43:06

标签: sockets go

如果没有goto语句,我怎样才能改进我的代码?

我的功能是从服务器读取并发送数据 到另一个处理数据的函数,我不得不添加一个 goto声明为了处理断开的连接情况, 我没有找到更好的方法来做到这一点。

你能帮我提一些建议吗?

func Reader(source string, proto string, chOutput chan string) {
init:
    fmt.Println("Conectando con Source:", source)
    conn, err := net.Dial(proto, source)
    if err != nil {
        fmt.Println("Error:", err.Error())
    }
    defer conn.Close()

    reader := bufio.NewReader(conn)

    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println("Error:", err.Error())
            time.Sleep(1 * time.Second)
            goto init
        }
        fmt.Println("Enviando dato a Buffer:", line)
        chOutput <- line
    }
}

我的功能是goroutine:

func main(){
    mychan:= make(chan string)
    go Reader(source, proto, mychan)
    go Process(mychan)
    ...

}

goto或标签是解决重试连接的最佳方法吗? 还有另一种标准方法吗?

2 个答案:

答案 0 :(得分:3)

您可以对错误处理来电者的问题并返回特殊错误:

var errRetry = errors.New("retry")

func Reader(source string, proto string, chOutput chan<- string) error {
    fmt.Println("Conectando con Source:", source)
    conn, err := net.Dial(proto, source)
    if err != nil {
        return err
    }
    defer conn.Close()

    scanner := bufio.NewScanner(conn)
    for scanner.Scan() {
        line := scanner.Text()
        fmt.Println("Enviando dato a Buffer:", line)
        chOutput <- line
    }
    if err := scanner.Err(); err != nil {
        return errRetry
    }
    return nil
}

func main() {
    ch := make(chan string)
    go func() {
        for s := range ch {
            // stuff with s
            _ = s
        }
    }()
L:
    for {
        switch err := Reader("localhost:9020", "tcp4", ch); err {
        case errRetry:
            // do nothing to retry
        case nil:
            // do you want to break if the connection got closed gracefully?
            break L
        default:
            //handle err
            break L
        }
    }
    close(ch)
}

答案 1 :(得分:0)

您可以通过引入外部循环来消除goto。如果打开连接时出现错误,请继续外循环。如果读取行有误,则跳出内循环。

完成后关闭连接。在函数返回之前,延迟不会执行。

func Reader(source string, proto string, chOutput chan string) {
  for {
    fmt.Println("Conectando con Source:", source)
    conn, err := net.Dial(proto, source)
    if err != nil {
        fmt.Println("Error:", err.Error())
        time.Sleep(1 * time.Second)
        continue
    }
    reader := bufio.NewReader(conn)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println("Error:", err.Error())
            conn.Close()
            time.Sleep(1 * time.Second)
            break
        }
        fmt.Println("Enviando dato a Buffer:", line)
        chOutput <- line
    }
  }
}

考虑在连接失败时使用指数退避:

func Reader(source string, proto string, chOutput chan string) {
  sleep := time.Second
  for {
    fmt.Println("Conectando con Source:", source)
    conn, err := net.Dial(proto, source)
    if err != nil {
        fmt.Println("Error:", err.Error())
        sleep *= 2 // exponential backoff
        if sleep > time.Minute {
           sleep = time.Minute
        }
        time.Sleep(sleep)
        continue
    }
    sleep = time.Second // Reset on success.
    reader := bufio.NewReader(conn)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println("Error:", err.Error())
            conn.Close()
            time.Sleep(sleep)
            break
        }
        fmt.Println("Enviando dato a Buffer:", line)
        chOutput <- line
    }
  }
}