Write on a closed net.Conn but returned nil error

先上一段简单的代码:

package main

import (

"fmt"

"time"

"net"

)

func main() {

addr := "127.0.0.1:8999"

// Server

go func() {

tcpaddr, err := net.ResolveTCPAddr("tcp4", addr)

if err != nil {

panic(err)

}

listen, err := net.ListenTCP("tcp", tcpaddr)

if err != nil {

panic(err)

}

for {

if conn, err := listen.Accept(); err != nil {

panic(err)

} else if conn != nil {

go func(conn net.Conn) {

buffer := make([]byte, 1024)

n, err := conn.Read(buffer)

if err != nil {

fmt.Println(err)

} else {

fmt.Println(">", string(buffer[0 : n]))

}

conn.Close()

}(conn)

}

}

}()

time.Sleep(time.Second)

// Client

if conn, err := net.Dial("tcp", addr); err == nil {

for i := 0; i < 2; i++ {

_, err := conn.Write([]byte("hello"))

if err != nil {

fmt.Println(err)

conn.Close()

break

} else {

fmt.Println("ok")

}

// sleep 10 seconds and re-send

time.Sleep(10*time.Second)

}

} else {

panic(err)

}

}

客户端往服务端发送数据,总共发送了两次,第一次过后服务端关闭了链接,过了10秒后客户端仍然使用同一个conn对象写入数据,并且返回Write方法返回成功。

这里旧奇了怪了,明明服务端都关闭了链接,并且都已经过了10秒客户端继续往同一个链接对象写数据,为啥还能成功呢?

有大神能解答一下么,非常感谢。

PS1:

为便于验证是否是缓冲区造成的问题,我尝试过将第二次发送设置很大的内容来进行发送,结果依旧是成功的,代码及截图如下:

// Client

if conn, err := net.Dial("tcp", addr); err == nil {

_, err := conn.Write([]byte("hello"))

if err != nil {

fmt.Println(err)

conn.Close()

return

} else {

fmt.Println("ok")

}

// sleep 10 seconds and re-send

time.Sleep(10*time.Second)

b := make([]byte, 40000)

for i := range b {

b[i] = 'x'

}

n, err := conn.Write(b)

if err != nil {

fmt.Println(err)

conn.Close()

return

} else {

fmt.Println("ok", n)

}

// sleep 10 seconds and re-send

time.Sleep(10*time.Second)

} else {

panic(err)

}

图片描述

PS2:

我用wireshark测试了一下,其实在Client第二次Write的时候,Client的TCP状态就已经是CLOSE_WAIT了,按理说这个状态就表示Server端(处于FIN_WAIT_2状态)已经不接收数据了(我试过Server端Close之后再Read操作会报错),那么这个时候Client再Write其实根本就没有什么意义了,那为什么Client端的Write还能成功呢?

wireshark:
图片描述

netstat:
图片描述

回答:

当服务器端执行 conn.Close() 后,服务器发送 FIN TCP 包给客户端,在客户端确认之后,该 TCP 连接变成“半开”(half-open)状态。

“半开”状态意味着服务器不能再向客户端发送数据,同理,客户端可以发送数据出去,因此 conn.Write() 不会报错。不过客户端最后一次发送的数据不会被服务器接收到。

你可以使用 wireshark 抓包分析 TCP 协议。

参考

[1] https://en.wikipedia.org/wiki...

回答:

你这个写法都错误了,代码注释地方。

package main

import (

"fmt"

"time"

"net"

)

func main() {

addr := "127.0.0.1:8999"

go func() {

tcpaddr, err := net.ResolveTCPAddr("tcp4", addr)

if err != nil {

panic(err)

}

listen, err := net.ListenTCP("tcp", tcpaddr)

if err != nil {

panic(err)

}

for {

if conn, err := listen.Accept(); err != nil {

panic(err)

} else if conn != nil {

go func(conn net.Conn) {

buffer := make([]byte, 1024)

n, err := conn.Read(buffer)

if err != nil {

fmt.Println(err)

} else {

fmt.Println(">", string(buffer[0 : n]))

}

conn.Close()//

}(conn)

}

}

}()

time.Sleep(time.Second)

// Client

if conn, err := net.Dial("tcp", addr); err == nil {

for i := 0; i < 2; i++ {

_, err := conn.Write([]byte("hello"))

if err != nil {

fmt.Println(err)

conn.Close()

break

} else {

fmt.Println("ok")

}

// sleep 10 seconds and re-send

time.Sleep(10*time.Second)

}

} else {

panic(err)

}

}

以上是 Write on a closed net.Conn but returned nil error 的全部内容, 来源链接: utcz.com/p/183229.html

回到顶部