'Golang TCP server gives "dial tcp 127.0.0.1:9999: connect: connection refused" error

I am learning from the book An Introduction to Programming in Go by Caleb Doxsey

In chapter 13 about servers we are given the code:

package main

import (
    "encoding/gob"
    "fmt"
    "net"
)

func server() {
    // listen on a port

    ln, err := net.Listen("tcp", ":9999")

    if err != nil {
        fmt.Println("server, Listen", err)
        return
    }

    for {
        // accept a connection
        c, err := ln.Accept()
        if err != nil {
            fmt.Println("server, Accept", err)
            continue
        }
        // handle the connection
        go handleServerConnection(c)
    }
}

func handleServerConnection(c net.Conn) {
    // receive the message
    var msg string
    err := gob.NewDecoder(c).Decode(&msg)
    if err != nil {
        fmt.Println("handleServerConnection", err)
    } else {
        fmt.Println("Received", msg)
    }

    c.Close()
}

func client() {
    // connect to the server
    c, err := net.Dial("tcp", "127.0.0.1:9999")
    if err != nil {
        fmt.Println("client, Dial", err)
        return
    }

    // send the message
    msg := "Hello World"
    fmt.Println("Sending", msg)
    err = gob.NewEncoder(c).Encode(msg)
    if err != nil {
        fmt.Println("client, NewEncoder", err)
    }

    c.Close()
}

func main() {
    go server()
    go client()
    
    var input string
    fmt.Scanln(&input)
}

Running this code I almost always receive:

client, Dial dial tcp 127.0.0.1:9999: connect: connection refused

But sometimes I receive:

Sending Hello World

Received Hello World

I have also discovered if I run just run server separately from client, and then run client on a separate file, it works as intended. Why is that?

go


Solution 1:[1]

Listen and Dial are called concurrently, and you can't predict which one executes first. If Dial executes before Listen then there is obviously nothing listening yet and that produces the error.

Call Listen in main, before starting the goroutines:

func main() {
    ln, err := net.Listen("tcp", ":9999")
    if err != nil {
        fmt.Fatal("server, Listen", err)
    }

    go server(ln)
    go client()
    
    var input string
    fmt.Scanln(&input)
}

func server(ln net.Listener) {
    for {
        // accept a connection
        c, err := ln.Accept()
        if err != nil {
            fmt.Println("server, Accept", err)
            continue
        }
        // handle the connection
        go handleServerConnection(c)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter