前言

之前已经讲过基于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源码如下: