1.定义
TCP连接以后不主动断开连接.区别于短链接(三次握手四次分手算一次短链接),优点是避免短时间内重复连接所造成的信道资源以及网络资源的浪费
2.长连接断开的原因
进程被杀死
NAT超时
网络状态发生变化
其他不可抗因素(网络状态差、DHCP的租期等等 )
其中重点讲一下NAT(地址转换技术) https://blog.csdn.net/gui951753/article/details/79593307 总结一句话就是。多个私网ip地址通过端口号映射到一个公网ip地址进行通信. 但是这么做有个弊端:破坏了IP的端到端通信 为了维持这种映射关系必然需要一张映射表,在会话静默的这段时间,NAT网关会进行老化操作(节省资源),那么TCP连接很有可能断开,这就和长链接冲突
3.维持长链接方法
进程保活
心跳保活
断线重连
进程保活
进程保活
心跳保活
后面会讲
断线重连
监测到网络变化并且判断连接的有效性,如果失效,那么就重新连接(判断连接的有效性主要存在于心跳保活机制,所以下面会在心跳保活机制中一起讲)
4.心跳保活机制
心跳保活
(注意,心跳机制和轮询机制还是有区别的.心跳机制是在一个TCP连接上进行的,轮询是每隔一段时间进行一次TCP请求)
心跳机制的理论方案
理论方案
从上图可以看出,对于心跳机制方案设计的要点在于
心跳包的规格(内容 & 大小)
心跳发送的间隔时间
断线重连机制 (核心 = 如何 判断长连接的有效性)
心跳包的规格
心跳包 = 1个携带少量信息 & 大小在10字节内的信息包
间隔时间
不宜太长不宜太短.太短会有信令风暴,太长会误判成连接断开
重连
判断长连接是否有效的准则 = 服务器是否返回心跳应答 (分清存活和有效,存活仅仅表示没断开,可能阻塞无法发送接收,有效表示没断开且能正常通信)
额外说明:
TCP 协议自带 KeepAlive 的机制是否可替代心跳机制 无法替代.原因:TCP KeepAlive机制 的作用是检测连接的有无(死活),但无法检测连接是否有效。 “连接有效”的定义 = 双方具备发送 + 接收消息的能力
6.demo展示 (伪代码)
public class NativeTcpClient {
/**
* 保存发送的tcp指令集
*/
private final Map<Long, CommandEntry> callbackPool = new ConcurrentHashMap<Long, CommandEntry>();
/**
* 处理完网络后,真正处理数据的队列
*/
private final LinkedBlockingQueue<ResultEntry> mResultProcessedQueue = new LinkedBlockingQueue<ResultEntry>();
private NativeTcpClient() {
//启动线程做超时检查
new Thread(new TimeOutRunnable()).start();//每隔1s从callbackPool取数据看是否超时,超时就删除(NativeClient如果处理掉的话会poll掉)
/**
* 每发送一次tcp请求,NativeClient都会处理,并且从callbackPool中移除,如果没移除,要么还没处理到,要么超时
* 所以每次从callbackPool取数据,发送时间和当前时间的差只要超过一定时间,就可以认为是超时(30s)
*/
mResultProcessedThread = new HandlerThread("ResultProcessedThread");
mResultProcessedThread.start();
Handler handler = new Handler(mResultProcessedThread.getLooper());
handler.post(new ResultProcessedRunnable());//从mResultProcessedQueue取出数据进行notify,然后根据类型由不同的通知去处理
NativeClient.getInstance().addMessageListener(msgListener);//最终把NativeClient返回的数据放到mResultProcessedQueue里面
/**
* NativeClient类似于socket功能
* 当能成功返回数据的时候,就会通过这个listener把对应数据放到mResultProcessedQueue里面去.
* ResultProcessedRunnable会去取mResultProcessedQueue里面的数据进行处理
*/
}
}