Home > Mobile >  Can't get output from server in client sometime
Can't get output from server in client sometime

Time:12-09

I am learning golang and trying to write a simple server, but something wrong to get output from the server when testing.

Code

package main

import (
    log "log"
    net "net"
    _ "time"
)

func main() {
    listener, err := net.Listen("tcp", ":12345")
    if err != nil {
        log.Fatalln(err)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Println(err)
        }
        go ClientHandler(conn)
    }
}

func ClientHandler(conn net.Conn) {
    defer func() {
        if v := recover(); v != nil {
            log.Println("Catch a panic:", v)
            log.Println("Prevent the program from crashing")
        }
        if err := conn.Close(); err != nil {
            log.Println(err)
        }
    }()

    b := make([]byte, 8)
    _, err := conn.Read(b)
    if err != nil {
        panic(err)
    }

    if _, err := conn.Write(append(b, '\n')); err != nil {
        panic(err)
    }
    // time.Sleep(time.Millisecond * time.Duration(100))
}

Test method

I tested it with netcat in bash.

function test_server {
    for i in `seq 1 $1`; do
        echo -n "$i: "
        echo "askjaslkfjlskflask" | nc localhost 12345
    done
}

When the data is more than or equal to the server side b's buffer size , the output will be messed up.

$ # TEST 1
$ test_server 10
1: 2: askjaslk
3: askjaslk
4: 5: askjaslk
6: askjaslk
7: askjaslk
8: 9: 10: %

if less than or uncomment the time.Sleep(), all will be ok

$ # TEST 2
1: askja
2: askja
3: askja
4: askja
5: askja
6: askja
7: askja
8: askja
9: askja
10: askja

What's more, when I debug the code, nothing seems wrong and the output will be like TEST 2.

Question

Now I realize that I should use a for loop or a larger buffer b to receive whole data. However, I can't understand why the output is messed up. I think there should be no data transfered or whole data transfered like TEST 2.

Update the Question

It's the openbsd netcat caused that. So, the question is what happens when using openbsd netcat.

Conclusion

Close when still has unread data causes that problem

CodePudding user response:

What happens here is that the server does not read the full data from the client, then closes the connection. Closing a TCP connection with data still in the read buffer will cause the server to send a connection reset - which can also be seen as RST when doing a packet capture.

If the RST arrives at about the same time as the response from the server (the conn.Write) it might lead to the RST processed first, i.e. the response will not be processed but the connection will be considered closed. So here is a race condition which means that sometimes output will happen (response processed first) or not (RST processed first).

The time.Sleep changes the time between sending the response and sending the RST, so that there is enough time to handle the response by netcat before handling the later RST - which means guaranteed output.

  •  Tags:  
  • go
  • Related