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:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当服务器端执行
conn.Close()
后,服务器发送 FIN TCP 包给客户端,在客户端确认之后,该 TCP 连接变成“半开”(half-open)状态。“半开”状态意味着服务器不能再向客户端发送数据,同理,客户端可以发送数据出去,因此
conn.Write()
不会报错。不过客户端最后一次发送的数据不会被服务器接收到。你可以使用 wireshark 抓包分析 TCP 协议。
参考
[1] https://en.wikipedia.org/wiki...
你这个写法都错误了,代码注释地方。