前言
之前已经讲过基于mina框架tcp长连接的基本实现,大家感兴趣的话,可以参考以下
MINA实现TCP长连接(一)——客户端实现
MINA实现TCP长连接(二)——服务端实现
但是在前面的讲解中只是实现了基本的通讯,当出现数据传输的时候容易出现断包,粘包问题。
那么下面就来讲讲断包,粘包问题吧。
今天涉及以下内容:
数据通讯容易出现接收数据不全的几种情况
数据通讯结果不全实际表现
数据不全的解决办法
运行效果图及项目结构图
解决数据不全的类的源码
先来波效果图
2.gif
一.数据通讯容易出现接收数据不全的几种情况
在mina实现的长连接通讯过程中,数据的收发容易出现以下几种情况:
A包,B包
A包+B断包,B断包
A断包, A断包+B包
A包+B包
其中只有第一种情况是正常的,其他三种都是不正常的。下面看看断包,粘包在运行中的情况表现吧。
二.数据通讯结果不全实际表现
首先看看在客户端中关于数据收发时的字符集编码的设置吧,在客户端TmClientManager中有这样一行代码:
//设置编码过滤器
mConnector.getFilterChain().addLast("codec",new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
相应的在服务端TmServerManager中关于编码设置的代码如下:
// 协议解析,采用mina现成的UTF-8字符串处理方式
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
当在TmClientManager向服务端发送消息:abc,接收消息如下:
mina_tcp客户端发送消息:abc
mina_tcp客户端收到消息:我是服务端的亚瑟
这是正常的,当客户端发送消息:我是中国人,则出现以下情况:
======mina_tcp客户端开始建立连接========
=========mina_tcp客户端连接成功========
=========mina_tcp客户端连接异常========java.lang.RuntimeException: Expanded by 0 but that wasn't enough for '我是中国人'
这就是数据收发时断包,粘包造成的。
三.数据不全的解决办法
造成断包,粘包情况以后,则需要处理。这时就涉及数据包"加密"和"解密"的问题,说是"加密"和"解密",其实是处理数据分包问题了。ok,下面看看分包涉及到的几个类吧:
MessageCodecFactory:加密,解密工厂(解决发送接收数据粘包断包问题)
MinaMessageDecoder: 数据包解密(断包粘包处理)
MinaMessageEncoder:数据包加密(断包粘包处理)
MinaUtil:字节转换类
然后,这几个类需要在客户端和服务端都使用到,则在客户端TmClientManager编码处理如下:
//设置编码过滤器
mConnector.getFilterChain().addLast(TmClientManager.MINA_CODEC,new ProtocolCodecFilter(new MessageCodecFactory(Charset.forName(mConfig.getCharsetName()))));
然后在服务端TmServerManager编码处理如下:
//协议解析,采用mina现成的UTF-8字符串处理方式
acceptor.getFilterChain().addLast(TmServerManager.MINA_CODEC, new ProtocolCodecFilter(new MessageCodecFactory(Charset.forName(mCharsetName))));
最后让我们来看看这样设置后,客户端发送消息:我是中国人啊你是谁,我是亚瑟,你知道么,大家好一切都号,接收消息如下:
======mina_tcp客户端开始建立连接========
=========mina_tcp客户端连接成功========
mina_tcp客户端发送消息:我是中国人啊你是谁,我是亚瑟,你知道么,大家好一切都号
mina_tcp客户端收到消息:我是服务端的亚瑟
四.运行效果图及项目结构图
效果图如下
2.gif
项目结构图如下:
image.png
五.解决数据不全的类的源码
MessageCodecFactory源码如下: