改进网络代码,而无需使用goto语句处理断开的连接情况

How can I improve my code without a goto statement?

My function is reading from a server and sending data to another function that process the data, I had to add a goto statement in order to deal broken connection cases, I didn't find a better way to do that.

Could you help me with some advices, please?

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('
')
        if err != nil {
            fmt.Println("Error:", err.Error())
            time.Sleep(1 * time.Second)
            goto init
        }
        fmt.Println("Enviando dato a Buffer:", line)
        chOutput <- line
    }
}

My function is a goroutine :

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

}

Is goto or a label the best way to solve retry connections? Are there another standard way to do that?

You can eliminate the goto by introducing an outer loop. Continue the outer loop if there's error opening the connection. Break out of the inner loop if there's an error reading lines.

Close the connection when you are done with it. The defer does not execute until the function returns.

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('
')
        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
    }
  }
}

Consider using exponential backoff on connection failures:

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('
')
        if err != nil {
            fmt.Println("Error:", err.Error())
            conn.Close()
            time.Sleep(sleep)
            break
        }
        fmt.Println("Enviando dato a Buffer:", line)
        chOutput <- line
    }
  }
}

You could make error handling the caller's problem and return a special error:

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)
}