Socket echo server in go
Question: I'm trying to implement a simple socket echo server in go this is the code:

    
    
    package main
    
    import (
        "fmt"
        "net"
        "sync"
    )
    
    func echo_srv(c net.Conn, wg sync.WaitGroup) {
        defer c.Close()
        defer wg.Done()
    
        for {
                var msg []byte
    
                n, err := c.Read(msg)
                if err != nil {
                        fmt.Printf("ERROR: read\n")
                        fmt.Print(err)
                        return
                }
                fmt.Printf("SERVER: received %v bytes\n", n)
    
                n, err = c.Write(msg)
                if err != nil {
                        fmt.Printf("ERROR: write\n")
                        fmt.Print(err)
                        return
                }
                fmt.Printf("SERVER: sent %v bytes\n", n)
        }
    }
    
    func main() {
        var wg sync.WaitGroup
    
        ln, err := net.Listen("unix", "./sock_srv")
        if err != nil {
                fmt.Print(err)
                return
        }
        defer ln.Close()
    
        conn, err := ln.Accept()
        if err != nil {
                fmt.Print(err)
                return
        }
        wg.Add(1)
        go echo_srv(conn, wg)
    
        wg.Wait()
    }
    

For some reason as soon as a client connects, c.Read() does not block and the
error message is printed. So, my first question is: Shouldn't c.Read() block
until a client sends something to the socket?

And second: After printing the error message, the server does not terminate.
This is what I see when executing the program in gdb:

    
    
    (gdb) run                                                                    
    Starting program: src/sockets/server/server                                  
    warning: Could not load shared library symbols for linux-vdso.so.1.          
    Do you need "set solib-search-path" or "set sysroot"?                        
    [Thread debugging using libthread_db enabled]                                
    Using host libthread_db library "/usr/lib/libthread_db.so.1".                
    [New Thread 0x7fffe7806700 (LWP 28594)]                                      
    [New Thread 0x7fffe7005700 (LWP 28595)]                                      
    ERROR: read                                                                  
    EOF^C                                                                        
    Program received signal SIGINT, Interrupt.                                   
    runtime.epollwait () at /usr/lib/go/src/pkg/runtime/sys_linux_amd64.s:383    
    383             RET                                                          
    (gdb) info goroutines                                                        
      1  waiting runtime.park                                                    
      2  syscall runtime.goexit                                                  
    * 3  syscall runtime.entersyscallblock
    

I have similar echo servers in Python and C and they work fine. For
completeness I also post the socket client application below (it works fine
with my C and Python servers).

Client:

    
    
    package main
    
    import (
        "bufio"
        "fmt"
        "net"
        "os"
        "strings"
    )
    
    func main() {
        stdin := bufio.NewReader(os.Stdin)
    
        conn, err := net.Dial("unix", "./sock_srv")
        if err != nil {
                fmt.Print(err)
                return
        }
        defer conn.Close()
    
        for {
                fmt.Print("Enter message to transmit: ")
                msg, err := stdin.ReadString('\n')
                if err != nil {
                        fmt.Print(err)
                        return
                }
    
                msg = msg[:len(msg)-1]
                if (strings.ToLower(msg) == "quit") || (strings.ToLower(msg) == "exit") {
                        fmt.Println("bye")
                        return
                }
    
                n, err := conn.Write([]byte(msg))
                if err != nil {
                        fmt.Print(err)
                        return
                }
                fmt.Printf("CLIENT: sent %v bytes\n", n)
    
                n, err = conn.Read([]byte(msg))
                if err != nil {
                        fmt.Print(err)
                        return
                }
                fmt.Printf("CLIENT: received %v bytes\n", n)
    
                fmt.Println("Received message:", msg)
        }
    }
    


Answer: Here is a working `echo_srv` for you. You'll need @jnml's suggestion too!

  * actually allocate some buffer to receive into - you made a 0 byte buffer!
  * exit neatly on EOF
  * only write the bytes received with `msg[:n]`
    
        func echo_srv(c net.Conn, wg *sync.WaitGroup) {
        defer c.Close()
        defer wg.Done()
    
        for {
            msg := make([]byte, 1000)
    
            n, err := c.Read(msg)
            if err == io.EOF {
                fmt.Printf("SERVER: received EOF (%d bytes ignored)\n", n)
                return
            } else  if err != nil {
                fmt.Printf("ERROR: read\n")
                fmt.Print(err)
                return
            }
            fmt.Printf("SERVER: received %v bytes\n", n)
    
            n, err = c.Write(msg[:n])
            if err != nil {
                fmt.Printf("ERROR: write\n")
                fmt.Print(err)
                return
            }
            fmt.Printf("SERVER: sent %v bytes\n", n)
        }
    }
    

