Go中的双向连接

时间:2013-08-14 11:57:57

标签: go

我正在尝试在Go中进行简单的控制台聊天,只是为了练习。但是,我不知道如何从服务器发回消息。服务器只接收一条消息,然后关闭连接。我怎么能发送回复?

我一直在搜索并找到有关websockets的信息,但我认为它们用于与浏览器进行交互。

这是服务器的两个功能:

func runServer() {
    // Listen on a port
    listen, error := net.Listen("tcp", ":8272")

    // Handles eventual errors
    if error != nil {
        fmt.Println(error)
        return
    }

    fmt.Println("Listening in port 8272.")

    for {
        // Accepts connections
        con, error := listen.Accept()

        // Handles eventual errors
        if error != nil {
            fmt.Println(error)
            continue
        }

        fmt.Println("Connection accepted.")

        // Handles the connection
        go handleConnection(con)
    }
}

func handleConnection(con net.Conn) {
    fmt.Println("Handling connection.")

    var message string

    // Decodes the received message
    decoder := gob.NewDecoder(con)
    error := decoder.Decode(&message)

    // Checks for errors
    if error != nil {
        fmt.Println(error)
    } else {
        fmt.Println("Received", message)
    }

    // Closes the connection
    con.Close()
    fmt.Println("Connection closed.")
}

这是客户的功能:

func runClient() {
    // Connects to server
    con, error := net.Dial("tcp", "127.0.0.1:8272")

    // Handles eventual errors
    if error != nil {
        fmt.Println(error)
        return
    }

    fmt.Println("Connected to 127.0.0.1:8272.")

    // Sends a message
    message := "Hello world"
    encoder := gob.NewEncoder(con)
    error = encoder.Encode(message)

    // Checks for errors
    if error != nil {
        fmt.Println(error)
    }

    con.Close()

    fmt.Println("Message sent. Connection closed.")
}

提前致谢。

1 个答案:

答案 0 :(得分:3)

您的con对象是一种连接,其中包含ReadWrite方法:here。您应该循环连接,尝试Read传入数据,然后处理它并(可能)Write返回服务器响应。 (这里,bufferio包等可以帮助您以更方便的方式处理它,这只是低级ReadWriter接口)

文档显示了一个小example

go func(c net.Conn) {
    // Echo all incoming data.
    io.Copy(c, c)
    // Shut down the connection.
    c.Close()
}(conn)

仅处理第一条消息,然后关闭。您可以像这样处理每个传入的消息:

go func(c net.Conn) {
    // Infinite loop: Get data, copy them and start over
    for {
        // Echo all incoming data.
        io.Copy(c, c)
    }
    // Shut down the connection.
    c.Close()
}(conn)

当使用与您的服务器相关的任何内容替换io.Copy时,您的示例将是这样的:

func handleConnection(con net.Conn) {
    fmt.Println("Handling connection.")

    defer func() {
        // Closes the connection
        con.Close()
        fmt.Println("Connection closed.")
    }()

    var message string

    // Decodes the received message
    decoder := gob.NewDecoder(con)
    encoder := gob.NewEncoder(con)
    for {
        error := decoder.Decode(&message)

        // Checks for errors
        if error != nil {
            fmt.Println(error)
            // Exit the loop
            return
        } else {
            fmt.Println("Received", message)
            // Sending back
            if error = encoder.Encode(message); error != nil {
                 fmt.Println(error)
                 return
            } else {
                fmt.Println("Echo'd successfuly ! Waiting for next message...")
            }
        }
    }
}

此外,您应该使用程序包log而不是fmt来记录日志消息(但这与此无关)。

理解这一切是如何工作的好地方是浏览默认http服务器here的实现。

同样,您的客户端应使用相同的模式循环:

LOOP:
    Send data (e.g. encoder.Encode)
    Receive data (e.g. decoder.Decode)
    if problem or termination -> break out of loop
END
close connection