tcp 如何维护长连接

上次提到tcp数据流无边界特点 还有一个特点那就是

TCP协议中有长连接和短连接之分

目录结构:

1 socket 正常关闭会发生什么

2 socket 异常关闭会发生什么

存在2个疑问

3 无论是socket正常关闭和异常关闭 socket捕获不到

4 几种心跳包处理方案

 

 

tcp建立的终止

这里讨论的是 于一方首先关闭连接的情况 

socke正常关闭

流程:

  • 被动关闭一方接受完毕数据 然后发送 TCP flag Fin请求
  • 主动关闭一方 tcp状态 进入TIME-WAIT
  • 主动关闭一方 在在此期间内 该端口不能被任何程序重用 不能建立任何连接。这个期间称为平静时间(quiet time)

       

 

 

Q1 问题来了 TIME-WAIT状态持续大约2分钟内 俗称 平静时间(quiet time) ,存在意义是什么

 

根据tcp状态含义解释

TIME-WAIT:等待足够的时 ,确保远程TCP收到了终止请求的确认

远程TCP收ack确认这个条件 直接 CLOSE-WAIT状态进入CLOSED状态 最后一步会成功

 

但是我还是不明白存在意义 最底层接受太官方 不容易理解 有更加合理接受吗麻烦告知 假设网络是好的

我给出答案都被自己排除了

内核为了兼容业务 正常这从业务角度来考虑 在高并发情况下接受为啥对方不能发送Fin请求和接受ack请求

(1)在读取数据之后 业务处于死锁 耗时操作 未能发送closed请求 这个解释不合理 因为讨论是 对方发送clonsed请求 进入time_wait状态

(2)对比TCP连接队列溢出listen 函数 int backlog 全连接队列的大小 默认backlog 值是50

   如果同时超过50连接 无法完成三次握手 舍去 但是查到关闭操作是否有关闭队列? 这个解释不很合理

sokcet 异常关闭

  • 一方: 立刻发送reset标记,即使缓冲区里有带发送的数据
  • 另外一方:此时连接马上断开 中途释放一个连
13:44:40.870817 IP 10.69.61.134.55372 > VM-10-112-178-190.1024: Flags [R.], seq 674, ack 6854, win 0, length 0
  • 这个方式叫做 异常终止一个连接 异常释放(abortive release)

优点是什么

异常终止一个连接对应用程序来说有两个优点:

(1)丢弃任何待发数据并立即发送复位报文段;

(2) R S T的接收方会区分另一端执行的是异常关闭还是正常关闭。

          应用程序使用的A P I必须提供产生异常关闭而不是正常关闭的手段

快速结束一个连接

Q2 问题来了 如何减少TIME_WAIT时间

通过修改socket选项之SO_LINGER  发送reset标记 打破四次握手,

避免TIME_WAIT状态 

 

 

讨论一下异常情况下是否捕获正常或者异常终止连接

客户端主机四种:

  • 客户端崩溃 异常关闭 server收不到ACK
  • 客户端曾经崩溃,但已经重启   响应是一个复位reset 
  • 客户端主机活跃运行,但从服务器不可到达 T C P连接的双方都没有向对方发送数据
  • 服务器主机突然断电 T C P连接的双方都没有向对方发送数据
  • 服务器主机网线被拔出 T C P连接的双方都没有向对方发送数据
  • 服务器主机正常重启当 系统被操作员关闭时,所有的应用程序进程(也就是客户端进程)都将被终止,客户端TCP会在连接上发送一个FIN。

 

心跳检查几种方案

 

KeepAlive通过定时发送探测包来探测连接的对端是否存活

其实keepalive有两种,一种是TCP层的keepalive,另一种是HTTP层的Keep-Alive。

这里说的ttcp层的keepalive

也就是TCP的选项:SO_KEEPALIVE。

int keepAlive = 1;//设定KeepAlive   

int keepIdle = 5;//开始首次KeepAlive探测前的TCP空闭时间   

int keepInterval = 5;//两次KeepAlive探测间的时间间隔   

int keepCount = 3;//判定断开前的KeepAlive探测次数 

 

缺点:

1 有时候检查不到 断电、直接拔掉网线、防火墙这些断线 (呜呜呜)

/* keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由:

* 但自己的keepalive有这样的一个bug:

* 正常情况下,连接的另一端主动调用colse关闭连接,tcp会通知,我们知道了该连接已经关

* 闭。但是如果tcp连接的另一端突然掉线,或者重启断电,这个时候我们并不知道网络已经关闭。

* 而此时,如果有发送数据失败,tcp会自动进行重传。重传包的优先级高于keepalive,那就意

* 味着,我们的keepalive总是不能发送出去。 而此时,我们也并不知道该连接已经出错而中断。

* 在较长时间的重传失败之后,我们才会知道。即我们在重传超时后才知道连接失败.×

 

2 不直接通知异常而是 通过其他方式通知业务层连接出现异常

c++:

在程序中表现为,当tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的

* 响应包),select会返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT.

 

启动定时器来检查

心跳包一般来说都是在逻辑层发送空的echo包来实现的。

下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线

缺点:

  1. 对网络闪断情况处理不好
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 ..")



}

 

3 循环处理+sleep方式()

 

 

本章节内容:

 

心跳包实现考虑问题

1 是否能及时发现异常

2 明确通知业务层出现异常

 

下章预告:

TCP的交互数据流

Nagle算法

TCP的超时与重传

拥塞避免算法

TCP的成块数据流

滑动窗口

 

计划:

 

参考:

  • 用TCP/IP详解,卷1:协议
  • rfc793(tcp协议)

 

转载于:https://my.oschina.net/woyaoxue/blog/1603016

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值