简体   繁体   中英

How to manage connections returned by Accept() in golang?

For a tcp server, we ofter Listen() and Accept().

func main() {
    ln, err := net.Listen("tcp", ":6000")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    for {
        conn, err := ln.Accept()
        if err != nil {
            fmt.Println(err)
            continue
        }

        go handleConnection(conn)
    }
}

But there're 2 ways to handling the connection returned by Accept:

1

func handleConnection(c net.Conn) {
    buf := make([]byte, 4096)

    for {
        n, err := c.Read(buf)
        if err != nil || n == 0 {
            c.Close()
            break
        }
        n, err = c.Write(buf[0:n])
        if err != nil {
            c.Close()
            break
        }
    }
    fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
}

2

func handleConnection(c net.Conn) {
    defer c.Close()
    buf := make([]byte, 4096)   

    n, err := c.Read(buf)
    if err != nil || n == 0 {
        c.Close()
        break
    }
    n, err = c.Write(buf[0:n])
    if err != nil {
        c.Close()
        break
    }
    fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
}

Are these 2 approaches correct? It seems approach 1 reuses the connections. But how to indicate the client the EOF?

The two approaches do different things:

The first approach reads some data and writes it back until an error, or until 0 bytes are read.

The second approach reads once, writes that back, and then closes the connection.

The first approach does not "reuse" the connection. It is implementing a simple echo-like protocol that runs until the connection is terminated. The second approach echoes once and closes the connection.

This answer assumes that the goal of the program is to echo data back to the client. This answer includes information in comments by torek and limon.

The documentation for Read says

Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. Even if Read returns n < len(p), it may use all of p as scratch space during the call. If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.

The second program may not read all of the data because Read can return available data instead of waiting for more. The second program may not write all of the data because read can return data and an error.

Let's focus on the first program because it's more correct. The program can make multiple Read and Write calls on a connection, but that's not reusing the connection.

It's better to defer c.Close() at the beginning of the function than to sprinkle calls to c.Close() throughout the function. The defer ensures that the connection is closed no matter how the function exits.

func handleConnection(c net.Conn) {
    defer c.Close()
    buf := make([]byte, 4096)

    for {
        n, err := c.Read(buf)
        if err != nil || n == 0 {
            break
        }
        n, err = c.Write(buf[0:n])
        if err != nil {
            break
        }
    }
    fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
}

Read can return some data and and error. Handle any data returned before processing the error:

func handleConnection(c net.Conn) {
    defer c.Close()
    buf := make([]byte, 4096)

    for {
        n, er := c.Read(buf)
        if n > 0 {
            _, ew := c.Write(buf[:n])
            if ew != nil {
                break
            }
        }
        if er != nil {
            break
        }
    }
    fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
}

Use io.Copy instead of writing the copy logic in the application. The io.Copy function gets all of the details right. Also, io.Copy can use some lower level optimizations for copying data from one connection to another.

func handleConnection(c net.Conn) {
    defer c.Close()
    io.Copy(c, c)
    fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM