1

I am trying to learn the net package. I am listening for local connections on a port, and sending data to that port using echo -n "Server test.\n" | nc localhost 5000.

I always get an EOF error when reading the data, however. I checked the docs and this is only supposed to happen when there is no more input available, however I don't understand why this is happening here.

This is my code:

package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
)

// Connection details
type connection struct {
    host    string
    port    string
    network string
}

// Initialise a Listener on a given port
// Pass handling into seperate goroutine
func main() {
    localConn := connection{
            host:    "", // Localhost
            port:    "5000",
            network: "tcp",
    }

    listener, err := net.Listen(localConn.network, localConn.host+":"+localConn.port)
    checkError("Error listening: ", err)

    conn, err := listener.Accept()
    for {
            checkError("Error accepting: ", err)
            go handleRequest(conn)
    }
}

// Delegate handling of requests
func handleRequest(conn net.Conn) {
    // Read message up until newline delimiter
    message, err := bufio.NewReader(conn).ReadString('\n')
    checkError("Error reading: ", err)

    fmt.Println("Message recieved: ", string(message))
    conn.Write([]byte("Recieved message: " + string(message) + "\n"))

    conn.Close()
}

// Check if an error exists
// If so, print and exit program. (Not super robust!)
func checkError(message string, err error) {
    if err != nil {
            fmt.Println(message, err.Error())
            os.Exit(1)
    }
}
haz
  • 2,034
  • 4
  • 28
  • 52

2 Answers2

2

You appear to be using echo incorrectly. The flag -e interprets the two characters \n as a newline (check here).

Use the following command to send data to server:

echo -e "Server test.\n" | nc localhost 5000

Other than that you should also fix for loop:

for {
    conn, err := listener.Accept()
    checkError("Error accepting: ", err)
    go handleRequest(conn)
}

In your original code you are only one connection is ever accepted. After that the for loop simply starts more goroutines that try to read on a closed connection (error or not, first handleRequest call closes the connection).

abhink
  • 8,740
  • 1
  • 36
  • 48
1

One problem is on these lines:

conn, err := listener.Accept()
for {
        checkError("Error accepting: ", err)
        go handleRequest(conn)
}

The application starts goroutines in a loop to read the single connection. The first goroutine to read the connection is successful. The subsequent goroutines report an error.

Change the code to:

for {
        conn, err := listener.Accept()
        checkError("Error accepting: ", err)
        go handleRequest(conn)
}

The client is not sending a newline as expected by the server. Use this command to send the message:

echo "Server test." | nc localhost 5000
Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242