Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble reading from a socket in go

Tags:

go

sockets

I'm trying to learn the go language, and I'm writing a simple echo server. I'm having difficulty making it work, though.

func listen(server string) {
    var buf []byte

    listener, ok := net.Listen("tcp", server)
    if ok != nil {
        fmt.Fprintf(os.Stderr, "Could not listen on socket: %s\n", ok.String())
        return
    }
    conn, ok := listener.Accept()
    if ok != nil {
        fmt.Fprintf(os.Stderr, "Could not accept connection on socket: %s\n", ok.String())
        return
    }

    writelen, ok := conn.Write(strings.Bytes("Ready to receive\n"))
    if ok != nil {
        fmt.Fprintf(os.Stderr, "Could not write to socket: %s\n", ok.String())
    } else {
        fmt.Printf("Wrote %d bytes to socket\n", writelen)
    }

    for ;; {
        readlen, ok := conn.Read(buf)
        if ok != nil {
            fmt.Fprintf(os.Stderr, "Error when reading from socket: %s\n", ok.String())
            return
        }
        if readlen == 0 {
            fmt.Printf("Connection closed by remote host\n")
            return
        }

        fmt.Printf("Client at %s says '%s'\n", conn.RemoteAddr().String(), buf)
    }
}

I get the following output from this function:

[nathan@ebisu ~/src/go/echo_server] ./6.out 1234
Using port 1234
Wrote 17 bytes to socket
Error when reading from socket: EOF

This is what I see on the client:

[nathan@ebisu ~] telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Ready to receive
Connection closed by foreign host.

Any help would be appreciated (or pointers to resources; the go documentation on the sockets API leaves a little to be desired).

Thanks,

Nathan

like image 437
Nathan Avatar asked Feb 16 '10 04:02

Nathan


People also ask

How does socket read work?

It reads input from the user on the standard input stream, and then forwards that text to the echo server by writing the text to the socket. The server echoes the input back through the socket to the client. The client program reads and displays the data passed back to it from the server.

What does socket read return?

Behavior for sockets: The read() call reads data on a socket with descriptor fs and stores it in a buffer. The read() all applies only to connected sockets. This call returns up to N bytes of data. If there are fewer bytes available than requested, the call returns the number currently available.

What is a socket connect error?

Resolution. If you are getting a socket connect error when downloading the content filter database you may have a corrupt SSL client. The error message suggests that the process responsible for performing the download was unable to access the ssl-client data structure in memory.

Can you read and write from the same socket?

One thread reading and one thread writing will work as you expect. Sockets are full duplex, so you can read while you write and vice-versa. You'd have to worry if you had multiple writers, but this is not the case.


2 Answers

In your example, buf needs to have a definite size. You've declared it as a 0-length slice.

Declare it as:

var buf = make([]byte, 1024)
like image 173
marketer Avatar answered Oct 02 '22 17:10

marketer


Of course, if you want to learn, it is better to write it yourself but, if it helps, here is my own echo server in Go.

package main

import (
    "net";
    "os";
    "fmt";
)

func handle(conn *net.TCPConn) {
    fmt.Printf("Connection from %s\n", conn.RemoteAddr());
    message := make([]byte, 1024);
    // TODO: loop the read, we can have >1024 bytes
    n1, error := conn.Read(message);
    if error != nil {
        fmt.Printf("Cannot read: %s\n", error);
        os.Exit(1);
    }
    n2, error := conn.Write(message[0:n1]);
    if error != nil || n2 != n1 {
        fmt.Printf("Cannot write: %s\n", error);
        os.Exit(1);
    }
    fmt.Printf("Echoed %d bytes\n", n2);
    conn.Close();   // TODO: wait to see if more data? It would be better with telnet...
}

func main() {
    listen := ":7";
    addr, error := net.ResolveTCPAddr(listen);
    if error != nil {
        fmt.Printf("Cannot parse \"%s\": %s\n", listen, error);
        os.Exit(1);
    }
    listener, error := net.ListenTCP("tcp", addr);
    if error != nil {
        fmt.Printf("Cannot listen: %s\n", error);
        os.Exit(1);
    }
    for {   // ever...
        conn, error := listener.AcceptTCP();
        if error != nil {
            fmt.Printf("Cannot accept: %s\n", error);
            os.Exit(1);
        }
        go handle(conn);
    }
}
like image 44
bortzmeyer Avatar answered Oct 02 '22 17:10

bortzmeyer