最近开始学习 go,照着教程写了一个简单的 tcp server 的代码,实现了 5 秒客户端还没有任何的数据发送,就自动关闭当前连接。这个地方我用的是 time.afterfunc 来实现的 运行起来也达到了预期,但不知道为什么,明明当前连接已经关闭,处理连接的函数已经返回,但是里面的这个 time.afterfunc 包裹的函数继续执行,真是见鬼了。下面是代码
package main
import (
"fmt"
"net"
"time"
)
func main() {
l, err := net.Listen("tcp", ":8888")
if err != nil {
fmt.Println("listen 报错:", err)
return
}
defer l.Close()
fmt.Println("listen ok")
var i int
for {
if conn, err := l.Accept(); err != nil {
fmt.Println("accept 报错:", err)
break
} else {
i++
fmt.Printf("%d: 接收到新的连接\n", i)
go fmt.Println(handleconntimeout(conn, 5))
}
}
}
func handleconntimeout(conn net.Conn, timeout int) int {
b := make([]byte, 1024)
var closetimer *time.Timer
f := realfunc(conn)
closetimer = time.AfterFunc(time.Duration(timeout)*time.Second, f)
defer conn.Close()
for n, err := conn.Read(b); err == nil; n, err = conn.Read(b) {
closetimer.Reset(time.Duration(timeout) * time.Second)
fmt.Printf("收到来自 %s 的一共 %d 数量字节\n", conn.RemoteAddr(), n)
fmt.Println(string(b[:n]))
}
fmt.Println("连接报错")
return 10000
}
func closeconn(conn net.Conn) {
fmt.Println("时间到,关闭连接")
conn.Close()
}
func realfunc(conn net.Conn) func() {
return func() {
closeconn(conn)
}
}
我启动服务端,用客户端连接没有问题,等待 5 秒钟,服务端这边一切如预期的一样, 第一行出现:时间到,关闭连接 第二行出现:连接报错 第三行打印出 handleconntimeout 这个函数的返回值 1000
诡异的是,我这边如果主动关闭客户端,服务端出现的是 第一行打印出:连接报错 第二行打印出:handleconntimeout 的返回值 1000 我本来以为后面就不应该再继续出现任何东西了 结果过了 5 秒第三行打印出 时间到,连接关闭
奇怪了,这个明明应该在 handleconntimeout 里面存在的动作,
time.AfterFunc(time.Duration(timeout)*time.Second, f) 这个延后执行的函数,不是应该随着 handleconntimeout 的返回,不应该继续执行的啊 怎么后来还在继续执行 由于是初学 golang,高手懂的给指点指点。 谢谢
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.