Search code examples
gorecursiontcp

Golang: Recursive function for reconnecting a TCP client... Bad idea?


I have this working TCP client code. When it fails to Write or Read on the TCP connection, it creates a new connection with the recursive function tcpReconnect().

Is this safe or will it fill up the RAM? It is possible that it may be trying to reconnect over several days (weekend or holidays). This is code is part of a Driver that monitors the state of an industrial Machine.

Maybe there is a better solution for this problem. I was not able to find one.

PS: I don't like polling

package main

import (
    "fmt"
    "net"
    "time"
)

var pollTime = 1000 //ms
var host = "127.0.0.1"
var port = "11000"

func main() {
    finished := make(chan bool)
    go Driver()
    <-finished
}

func tcpReconnect() net.Conn {
    newConn, err := net.Dial("tcp", host+":"+port)
    if err != nil {
        fmt.Println("Failed to reconnect:", err.Error())
        time.Sleep(time.Millisecond * time.Duration(2000))
        newConn = tcpReconnect()
    }
    return newConn
}

func Driver() {
    var conn net.Conn
    conn, err := net.Dial("tcp", host+":"+port)
    if err != nil {
        fmt.Println("Failed to initialize Connection, trying to reconnect:", err.Error())
        conn = tcpReconnect()
    }

    for {
        _, err = conn.Write([]byte("11|5546|STATUS" + "\r\n"))
        if err != nil {
            println("Write to server failed:", err.Error())
            println("Trying reset the connection...")
            conn = tcpReconnect()
        }

        var replyBuffer = make([]byte, 256)
        _, err = conn.Read(replyBuffer)
        if err != nil {
            println("Read from server failed:", err.Error())
            println("Trying reset the connection...")
            conn = tcpReConnect()
        }

        var reply string
        for i, val := range replyBuffer {
            if val == 13 { //13 is CR and marks the end of the message
                reply = string(replyBuffer[:i])
                break
            }
        }

        fmt.Printf("reply from server=%s\n", reply)
        time.Sleep(time.Millisecond * time.Duration(pollTime))
    }
}

Solution

  • This is what I came up with. Credits go to @tkausl and @ThunderCat

    func Driver() {
        for {
            conn, err := net.Dial("tcp", host+":"+port)
            if err != nil {
                fmt.Println("Failed to connect:", err.Error())
                fmt.Println("Trying reset the connection...")
                time.Sleep(time.Millisecond * time.Duration(2000))
            } else {
                for {
    
                    _, err = conn.Write([]byte("11|5546|STATUS" + "\r\n"))
                    if err != nil {
                        fmt.Println("Write to server failed:", err.Error())
                        fmt.Println("Trying reset the connection...")
                        break
                    }
    
                    var replyBuffer = make([]byte, 256)
                    _, err = conn.Read(replyBuffer)
                    if err != nil {
                        fmt.Println("Read from server failed:", err.Error())
                        fmt.Println("Trying reset the connection...")
                        break
                    }
    
                    var reply string
                    for i, val := range replyBuffer {
                        if val == 13 { //13 is CR and marks the end of the message
                            reply = string(replyBuffer[:i])
                            break
                        }
                    }
    
                    fmt.Printf("reply from server=_%s_\n", reply)
                    time.Sleep(time.Millisecond * time.Duration(pollTime))
                }
            }
        }
    }