上次提到tcp数据流无边界特点
还有一个特点那就是
TCP有长连接和短连接之分
tcp连接的终止
—
01
—
socke正常关闭
流程:
分析处于 T I M E _ WA I T状态的主机收到使其进入此状态的重复的 F I N时 所发生的情况。--重新计时
Q1 问题来了 TIME-WAIT 影响了端口马上被重用存在意义?
根据tcp状态含义解释 TIME-WAIT:等待足够的时 (等待),确保远程TCP收到了终止请求的确认 远程TCP收ack确认(这个条件) 直接 CLOSE-WAIT状态进入CLOSED状态 目的保证最后一步ack安全到达
但是我还是不明白存在意义 有更加合理解释吗?
—
02
—
sokcet 异常关闭
分析处于T I M E _ WA I T状态的主机收到一个 R S T时所发生的情况。
--断开连接
Q2 问题来了 如何减少TIME_WAIT时间
通过修改socket选项SO_LINGER 异常关闭连接 打破四次握手, 避免j进入TIME_WAIT状态
—
03
—
异常情况
心跳检查几种方案
—
04
—
TCP KeepAlive通过定时发送探测
缺点:
1 有时候检查不到 断电、直接拔掉网线、防火墙这些断线 (呜呜呜)
keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由: 但自己的keepalive有这样的一个bug: 正常情况下,连接的另一端主动调用colse关闭连接,tcp会通知,我们知道了该连接已经关闭。 但是如果tcp连接的另一端突然掉线,或者重启断电,这个时候我们并不知道网络已经关闭。 而此时,如果有发送数据失败,tcp会自动进行重传。重传包的优先级高于keepalive,那就意 味着,我们的keepalive总是不能发送出去。 而此时,我们也并不知道该连接已经出错而中断。 在较长时间的重传失败之后,我们才会知道。即我们在重传超时后才知道连接失败.
—
05
—
不直接通知异常
c++: 在程序中表现为,当tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的 * 响应包),select会返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT.
—
06
—
启动定时器来检查
缺点:
func (pthis *SocketClient) RecHeartBeating() {
log.Println("RecHeartBeating begin ..")
var ticker *time.Timer
ticker = time.NewTimer(time.Second * 10)
defer ticker.Stop()
for {
select {
case _ = <-pthis.heartChannel:
log.Println(pthis.conn.RemoteAddr().String(), "get message, keeping heartbeating...")
//conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second)) ticker.Reset(time.Second * 10)
break case <-ticker.C:
log.Println(" RecHeartBeating timeout!!!")
pthis.userLeaveOp()
pthis.conn.Close()
}
}
log.Println("RecHeartBeating end ..")
}// 心跳计时,判断Client是否在设定时间内发来信息func (pthis *SocketClient) SendHeartBeating() {
log.Println("SendHeartBeating begin ..")
for {
select {
case <-time.After(time.Second * 5):
log.Println(" SendHeartBeating!!!")
data := "HeartBeating" pthis.send(pthis.conn, heartReq, data)
}
}
log.Println("SendHeartBeating end ..")
}
—
07
—
自己实现
大纲
心跳包实现考虑问题
1 是否能及时发现异常
2 明确通知业务层出现异常