进入套接字echo服务器

sko*_*gon 4 sockets go

我正在尝试实现一个简单的套接字echo服务器,这是代码:

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()
}
Run Code Online (Sandbox Code Playgroud)

出于某种原因,只要客户端连接,c.Read()就不会阻止并打印错误消息.所以,我的第一个问题是:在客户端向套接字发送内容之前,是否应该阻止c.Read()阻塞?

第二:打印错误消息后,服务器不会终止.这是我在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
Run Code Online (Sandbox Code Playgroud)

我在Python和C中有类似的echo服务器,它们工作正常.为了完整性,我还发布了下面的套接字客户端应用程序(它适用于我的C和Python服务器).

客户:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*ood 5

这是echo_srv适合你的.你也需要@ jnml的建议!

  • 实际上分配一些缓冲区来接收 - 你做了一个0字节的缓冲区!
  • 在EOF上整齐地退出
  • 只写下收到的字节 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)
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)