有时无法从客户端中的服务器获取输出



我正在学习golang,并试图编写一个简单的服务器,但在测试时从服务器获得输出时出现了问题。

代码

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))
}

试验方法

我在bash中用netcat测试了它。

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

当数据大于或等于服务器端b的缓冲区大小时,输出将被打乱。

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

如果小于或取消注释time.Sleep(),则将全部正常

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

更重要的是,当我调试代码时,似乎没有什么问题,输出将像TEST2一样。

问题

现在我意识到我应该使用for循环或更大的缓冲区b来接收整个数据。然而,我不明白为什么输出会一团糟。我认为不应该有数据传输或整个数据传输像测试2。

更新问题

是openbsd netcat造成的。所以,问题是当使用openbsd-netcat时会发生什么。

结论

Close当仍有未读数据时会导致问题

这里发生的情况是服务器没有从客户端读取完整的数据,然后关闭连接。关闭数据仍在读取缓冲区中的TCP连接将导致服务器发送连接重置-在进行数据包捕获时,这也可以被视为RST。

如果RST与来自服务器(conn.Write(的响应大约在同一时间到达,则可能导致RST首先被处理,即响应将不被处理,但连接将被视为关闭。所以这里有一个竞争条件,这意味着有时会发生输出(首先处理响应(或不发生输出(先处理RST(。

time.Sleep改变了发送响应和发送RST之间的时间,以便在处理后面的RST之前有足够的时间由netcat处理响应,这意味着有保证的输出。

最新更新