MINA2中(MINA2 RC版本,MINA2.0正式版已经发布)服务端接受数据默认有一定长度的缓冲区(可以在启动的时候设置)。那么对于大报文,怎么处理呢?比如说超过1024,甚至更多?MINA2为了节省网络流量,提高处理效率,会将大报文自动拆分(可能是存放MINA2中的缓冲区里面):比如2048字节的报文,就会拆分成两次;那么在接受的时候,就有一个如何判断是完整报文的问题,或者说是一个拆包组包的问题。
MINA2中初始化服务的时候是可以设置输入和输出的缓冲区的:
acceptor.getSessionConfig().setReadBufferSize(1024);
MINA2提供的案例是,在IoSession中设置一个类似于session,存在在当前IoSession中的全局变量,在此IoSession中有效。
private final AttributeKey TEST = new AttributeKey(getClass(), "TEST");
大家都知道,通过 SOCKET TCP/IP传输过来的报文是不知道边界的,所以一般会约定在前端固定长度的字节加上报文长度,让SERVER来根据这个长度来确定整个报文的边界,在我前面的博文有提到。其实MINA2中有:
prefixedDataAvailable(4) int
方法,来判断固定长度的报文长度,但是参数只能是1,2,4;该方法很好用。判断前四字节的整型值是否大于等于整个缓冲区的数据。可以方便的判断一次 messageReceived 过来的数据是否完整。(前提是自己设计的网络通讯协议前四字节等于发送数据的长度) ,如果你不是设定1,2,4字节来作为长度的话,那么就没辙了。
在你的解码操作中,MINA2的缓冲区发多少次报文,你的decode方法就会调用多少次。
上面设置了session之后,可以采用一个方法:
/**
*
* @param session
* 会话信息
* @return 返回session中的累积
*/
private Context getContext(IoSession session) {
Context ctx = (Context) session.getAttribute(CONTEXT);
if (ctx == null) {
ctx = new Context();
session.setAttribute(CONTEXT, ctx);
}
return ctx;
}
然后在你的decode方法中,首先从session取出数据对象,进行拼接:
Context ctx = getContext(session);
// 先把当前buffer中的数据追加到Context的buffer当中
ctx.append(ioBuffer);
// 把position指向0位置,把limit指向原来的position位置
IoBuffer buf = ctx.getBuffer();
buf.flip();
接着读取每次报文的总长度:
// 读取消息头部分
byte[] bLeng = new byte[packHeadLength];
buf.get(bLeng);
int length = -1;
try {
length = Integer.parseInt(new String(bLeng));
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
if (length > 0) {
ctx.setMsgLength(length);
}
在读取到每次报文的长度之后,就接着循环判断BUF里面的字节数据是否已经全部接受完毕了,如果没有接受完毕,那么就不处理;下面是完整处理的代码:
while (buf.remaining() >= packHeadLength) {
buf.mark();
// 设置总长度
if (ctx.getMsgLength() <= 0) {
// 读取消息头部分
byte[] bLeng = new byte[packHeadLength];
buf.get(bLeng);
int length = -1;
try {
length = Integer.parseInt(new String(bLeng));
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
if (length > 0) {
ctx.setMsgLength(length);
}
}
// 读取消息头部分
int length = ctx.getMsgLength();
// 检查读取的包头是否正常,不正常的话清空buffer
if (length < 0) { // || length > maxPackLength2) {
buf.clear();
out.write("ERROR!");
break;
// 读取正常的消息包,并写入输出流中,以便IoHandler进行处理
} else if (length > packHeadLength && buf.remaining() >= length) {
//完整的数据读取之后,就可以开始做你自己想做的操作了
} else {
// 如果消息包不完整
// 将指针重新移动消息头的起始位置
buf.reset();
break;
}
}
if (buf.hasRemaining()) { // 如果有剩余的数据,则放入Session中
// 将数据移到buffer的最前面
IoBuffer temp = IoBuffer.allocate(2048).setAutoExpand(
true);
temp.put(buf);
temp.flip();
buf.clear();
buf.put(temp);
} else { // 如果数据已经处理完毕,进行清空
buf.clear();
}
为了便于操作,最好设置一个内部类:
private class Context {
private final CharsetDecoder decoder;
private IoBuffer buf;
private int msgLength = 0;
private int overflowPosition = 0;
/**
*
*
*/
private Context() {
decoder = charset.newDecoder();
buf = IoBuffer.allocate(80).setAutoExpand(true);
}
/**
*
*
* @return CharsetDecoder
*/
public CharsetDecoder getDecoder() {
return decoder;
}
/**
*
*
* @return IoBuffer
*/
public IoBuffer getBuffer() {
return buf;
}
/**
*
*
* @return overflowPosition
*/
public int getOverflowPosition() {
return overflowPosition;
}
/**
*
*
* @return matchCount
*/
public int getMsgLength() {
return msgLength;
}
/**
*
*
* @param matchCount
* 报文长度
*/
public void setMsgLength(int msgLength) {
this.msgLength = msgLength;
}
/**
*
*
*/
public void reset() {
this.buf.clear();
this.overflowPosition = 0;
this.msgLength = 0;
this.decoder.reset();
}
/**
*
* @param in
* 输入流
*/
public void append(IoBuffer in) {
getBuffer().put(in);
}
}
分享到:
相关推荐
本实例主要关注的是Mina在处理网络通信时遇到的两个常见问题——“断包”和“粘包”。 1. **断包**: 当数据在网络中传输时,可能会因为各种原因(如网络拥塞、数据包大小限制等)被分割成多个部分,这些部分在...
2. 分析服务端代码,找到自定义解码器的部分,理解它是如何处理粘包和断包的。 3. 查看客户端代码,了解数据编码过程,以及如何发送这些编码后的数据。 4. 运行服务端和客户端,进行实际测试,观察是否解决了断包和...
mina 协议 解包 粘包
2. **Mina文件图片传送** 在Mina中,我们可以利用BufferedIoFilter或者IoBuffer来传输文件,包括图片。首先,我们需要将图片文件读取到内存中的IoBuffer,然后通过过滤器链传递给远程客户端。在这个过程中,可以...
MINA2的强大之处在于它为开发者提供了异步事件驱动的网络通信框架,免去了处理底层网络编程的复杂性,如多线程管理和数据缓冲等。 MINA2的核心概念包括: 1. **IoSession**:IoSession 是 MINA 中的核心接口,它...
MINA2作为其最新版本,尤其在处理大量并发连接时展现出了卓越的能力,如"mina2核心框架5000个并发"所示,它能够轻松应对高负载环境,为开发者提供了稳定且高效的网络编程解决方案。 MINA2的核心特性包括: 1. **...
《MINA2推送Demo客户端详解及应用...通过对这个例子的深入学习和实践,开发者不仅可以掌握MINA2的基本用法,还能了解到如何利用MINA2构建高效、可靠的网络应用,这对于任何致力于网络编程的开发者来说都是宝贵的资源。
4. **MINA2的UDP服务端**:MINA2服务端会创建一个Acceptor监听特定的UDP端口,接收到数据后通过FilterChain进行处理,然后可能发送回相应的数据。 5. **过滤器(Filter)**:MINA2中的过滤器是处理输入和输出数据的...
**Mina2.x开发示例** Apache Mina是一个开源项目,提供了一个高度可扩展的网络通信框架,适用于各种协议,如TCP、UDP和HTTP。它主要用于简化开发高性能、高并发的网络应用程序,如服务器和客户端。在Mina2.x版本中...
处理Bytes粘包、半包、断包(ByteArrayDecoder),需配置自己的首尾标识符, 如果与首尾标识符相同的数据出现在首尾标识符以内的范围,建议将该数据进行转义, 如这样配置转义规则(假设首尾标识符是0x7e): 0x7e = 0x...
标题"mina2 源码 mina"暗示我们将探讨MINA2的源代码,这是一个非常有价值的资源,对于理解MINA的工作原理、学习如何构建网络应用程序以及定制MINA的行为非常有用。MINA的源码包含了丰富的注释和示例,可以帮助开发者...
在串口通信中,Mina可以处理底层的I/O操作,如打开串口、设置波特率、奇偶校验等,并提供了事件驱动模型,使得我们可以方便地监听和响应串口事件。 "粘包"和"断包"是网络通信中常见的问题。当数据包边界不清晰时,...
Mina2作为一个轻量级的网络通信框架,提供了高度抽象的API,使得开发者可以方便地处理网络I/O操作。而Spring框架以其强大的依赖注入和面向切面编程特性,简化了Java应用的复杂性。当这两个框架相结合时,可以创建出...
通过深入研究Mina2的源码,我们可以了解到如何优化网络通信性能,如何处理大规模并发连接,以及如何设计和实现自己的网络协议。源码分析还能帮助我们理解Java的多线程、并发控制和事件驱动编程等高级特性,提升我们...
2. **事件驱动**:MINA基于事件驱动的设计,通过监听网络事件(如连接建立、数据到达等)来触发相应的处理逻辑,简化了复杂网络应用的编程。 3. **异步通信**:MINA的异步通信模式意味着发送请求后无需等待响应,...
5. **MINA2事件驱动模型**:MINA2基于事件驱动模型,通过事件触发器IoAdapter来处理网络事件,如连接建立、数据到达、连接关闭等。这种模型能有效利用多线程,提高并发处理能力。 6. **API文档**:英文版的MINA2 ...
IoFilter则是一个过滤器链,允许在数据传输到IoHandler之前对其进行预处理或在之后进行后处理。通过IoFilter,你可以实现认证、加密、压缩等各种功能,增强了MINA的灵活性和可扩展性。 在MINA中,ByteBuffer的使用...
使用Mina2创建Socket连接,首先需要定义一个服务端的ProtocolHandler,处理接收到的数据。然后启动Acceptor监听特定端口,等待客户端连接。客户端通过Connector发起连接请求,连接成功后,双方都可以通过Session...