defer func() {
err := conn.Close()
fmt.Println(“Client connect closed !”)
if err != nil {
fmt.Println(err)
}
}()
fmt.Println(conn.LocalAddr().String() + " : Client connected!")
time.Sleep(10 * time.Second)
运行后,效果如下,也符合我们预期:当程序打印 Client connected! 时,能看到连接,当打印 Client connect closed! 时,连接断开
如果我们在连接断开前使用 kill -9 强杀进程呢?(这里我用了两台电脑来测试)
我们发现 conn.Close() 并没有执行,但四次挥手还是发生了!
查阅资料发现如下结论:
a、b 两个正常连接的对端进程。假如 b 进程没有调用 close 就异常终止,那么发送 FIN 包是内核 OS 代劳
断电/断网时的连接是怎样断开的
===============
我们通过上面的实验发现就算进程异常终止,操作系统也会帮忙发起四次挥手
但如果是断电或断网的情况下,操作系统就无法代劳了,这时会怎样呢?为了便于测试,这里用两台电脑,client 连接 server,断开 server 的网络来模拟断网断电情况。
可以肯定的是 断网,断电后,连接不会立即断开 ,那么后续连接是否会断开呢?我们分成下面几种情况来看
断网时有数据传输
========
断网时如果有数据发送,由于收不到 ACK,所以会重试,但并不会无限重试下去,达到一定的重发次数之后,如果仍然没有任何确认应答返回,就会判断为网络或者对端主机发生了异常,强制关闭连接。此时的关闭是直接关闭,而没有挥手(数据都发不出去,还挥啥手),Linux 下的设置为
最小重传时间是200ms 最大重传时间是120s 重传次数为15
断网时没有数据传输
=========
断网时如果没有数据传输,还得看 TCP 连接的 KeepAlive 是否打开,关于 TCP 的 KeepAlive 简介如下:
-
TCP KeepAlive 是一种在不影响数据流内容的情况下探测对方的方式,采用保活计时器 实现,当计时器被触发时,一端发送保活报文,另一端接收到报文后发送 ACK 响应
-
它并不是 TCP 的规范,但大部分的实现都提供了这一机制
-
该机制存在争议,有的人保活机制应该在应用程序中实现
开启KeepAlive
===========
操作系统中有这么几个参数控制 KeepAlive 的配置:
-
Keepalive_time:空闲时间,即多长时间连接没有发送数据时开始 KeepAlive 检测
-
Keepalive_intvl:发送间隔时间,即上述代码的设置
-
Keepalive_probs:最多发送多少个检测数据包
在 Linux 上可以通过如下文件查看
cat /proc/sys/net/ipv4/tcp_keepalive_time
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
cat /proc/sys/net/ipv4/tcp_keepalive_probes
如果按照这个默认值来看,得2小时没有数据传输,KeepAlive 才开始工作!
而在 Go 中只有两个参数可以设置:
conn.SetKeepAlive(true)
conn.SetKeepAlivePeriod(5 * time.Second)
其中第二个 SetKeepAlivePeriod 源码是这样的:
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
// The kernel expects seconds so round to next highest second.
secs := int(roundDurationUp(d, time.Second))
if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err != nil {
return wrapSyscallError(“setsockopt”, err)
}
err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs)
runtime.KeepAlive(fd)
return wrapSyscallError(“setsockopt”, err)
}
SetKeepAlivePeriod 的参数同时设置了 tcp_keepalive_intvl 和 tcp_keepalive_time,tcp_keepalive_probes 没法设置
做个简单测试:client 开启 KeepAlive 连接 server 后,什么数据都不发送,把server 的网断掉,可以看到 KeepAlive 心跳包,一段时间后连接被置为 CLOSED 状态
关闭KeepAlive
===========
关闭 KeepAlive 后,如果没有数据传输,连接永远不会断开
断网后 server 重启再恢复
================
再思考一个场景,如果 client 与 server 建立连接后,没有数据传输,断掉 server 端的网络,这时如果把 server 程序重启一下,再恢复网络,那这条连接还能用吗?
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
最后
这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)
img-HNgcLXSI-1710393826093)]
最后
这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)
[外链图片转存中…(img-dViWfW8j-1710393826093)]
[外链图片转存中…(img-H35JRPYZ-1710393826094)]