go - 创建服务器并连接到它

标签 go networking server goroutine

我正在尝试创建一个服务器并在 Go 中连接到它,但是当服务器开始运行时,调用它之后没有任何函数,因为启动服务器的函数似乎被阻塞了。我尝试使用 goroutine 在后台运行服务器,以便可以执行其他代码,但这也没有真正起作用。我收到一个我不明白的错误

panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x496757]

这是我的服务器代码

func RunServer(port string) {

    fmt.Println("Launching server...")
    ln, err := net.Listen("tcp", port)
    conn, _ := ln.Accept()

    // run loop forever (or until ctrl-c)
    for {

        // will listen for message to process ending in newline (\n)
        message, _ := bufio.NewReader(conn).ReadString('\n')

        // output message received
        fmt.Print("Message Received:", string(message))

        // sample process for string received
        newmessage := strings.ToUpper(message)

        // send new string back to client
        conn.Write([]byte(newmessage + "\n"))
    }
}

这是客户端的代码。

func createInitalClient(port int) {

    // run server then create a client that connects to it
    portToRunOn := fmt.Sprintf("%s%d", ":", port)
    go RunServer(portToRunOn)
}

func main() {

    createInitalClient(5000)

    // connect to this socket
    conn, _ := net.Dial("tcp", "127.0.0.1:5000")

    for {
        // read in input from stdin

        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Text to send: ")
        text, _ := reader.ReadString('\n')

        // send to socket
        fmt.Fprintf(conn, text+"\n")

        // listen for reply
        message, _ := bufio.NewReader(conn).ReadString('\n')
        fmt.Print("Message from server: " + message)
    }
}

我这样做是否正确,或者是否有其他方法可以完成我想做的事情?我对使用 goroutines 有点犹豫,因为在我的情况下引入异步行为可能是错误的。

编辑 1:看起来发生此错误是因为客户端在服务器启动之前尝试连接到服务器。

编辑 2:我(可能已经)通过在服务器中添加一个 bool channel 来修复此问题,该 channel 在监听器开始接受连接之前立即返回 true。然后,如果来自 channel 的值为真,则客户端仅连接到服务器。我不确定在这种情况下这是否是正确的修复方法,但它似乎有效。

最佳答案

您的服务器在 goroutine 中启动,该 goroutine 由 Go 运行时异步生成,需要一些时间来安排和执行。具体来说,运行时不会等待服务器 goroutine 启动,然后继续执行 main 函数。

您要么需要:

  • 安排服务器 goroutine 在服务器准备好接受连接时进行通信——使用 channel 是一种可接受的机制;或
  • 让您的客户端连接尝试重复连接,直到连接被接受——实际上轮询服务器的就绪状态。例如:

    // Predeclare "conn" to ensure it remains in scope outside the loop
    var conn net.Conn
    
    for {
        var err error
        conn, err = net.Dial("tcp", "127.0.0.1:5000")
    
        // Failed connection, try again in a second.
        // TODO: limit the number of attempts before giving up.
        if err != nil {
            time.Sleep(time.Second)
            continue
        }
    
        // Connected successfully. Continue.
        break
    }
    
    // do something with "conn"
    

错误值

正如在对您的问题的评论中指出的,您的代码在多个地方忽略了错误值。

请不要在实际生产代码中这样做。返回错误是有原因的,并且可能表明代码外部存在问题,导致程序无法正常继续执行。您需要检查错误值并在错误值返回时采取适当的措施。如果返回的 error 不是 nil,则从函数调用返回的其他值(尤其是标准库中的任何值)不太可能有意义。

是的,你最终写了很多 if err != nil 。这是预料之中的,在某些情况下您可以采用各种模式来避免让您的代码看起来过于重复。

关于go - 创建服务器并连接到它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52458120/

相关文章:

powershell - 在 PowerShell 中获取特定网络信息

svn - Subversion 服务器与通过 Tortoise 的网络存储库访问

php - Ubuntu iptable 搞砸 file_get_contents()

go - 如何在不不断传递用户名/密码的情况下识别 Go 服务器上的用户

windows - 服务器端 FTP 批处理脚本

go - 上下文取消不退出

go - 如何在 Go 编程语言中可靠地 unlink() Unix 域套接字

Golang - 丢弃为 WriteCloser

http - 无法成功实现 http.Handler

java - 使用java设置http服务器