mina 在发送长报文时,为什么被截成好几段呢。请大侠帮帮忙。

jinfengwei1987 2011-10-30 10:42:16
mina 在发送长报文时,为什么被截成好几段呢。请大侠帮帮忙。
...全文
770 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
业余草 2013-12-06
  • 打赏
  • 举报
回复
能不能把你的mina1的例子发给我看看,邮箱xmt1990@126.com
shine333 2011-10-30
  • 打赏
  • 举报
回复
这个是必然的。物理限制,和mina无关。

你使用的默认解码器或者自己写的解码器的一个功能,就是将可能的N个物理包,变成一个逻辑包。每个逻辑包,包头应当由标志位(这个逻辑包是什么数据)以及长度位(这个逻辑包长度是多少,个别固定长度的逻辑包,可以省略)。

每次,解码的时候,读取bytebuffer的头,看看当前解析的是什么包,然后长度是多少,再比较一下,当前的bytebuffer长度够不够,如果不够的话,则将bytebuffer的指针重新mark到0,并不处理当前的bytebuffer
下次接收到的物理包的bytebuffer会和这次没解析玩的拼在一起,位置还是在这个逻辑包的开头位置,一直到接收到足够的数据。

另外,要注意的是,最后一个包,可能还包含下一次的逻辑包的开头部分,在解析完当前包的时候,要注意最后把position设置到正确位置。以免下一个逻辑包丢数据。

下面是一个我很早前些的mina 1的例子

// $Id: AbstractPacketDecoder.java,v 1.5 2008/06/15 19:07:27 michael Exp $
package xxx.codec.decoder;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoderAdapter;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;

/**
* 数据包解码对象解码器抽象超类。
*
* @version $Revision: 1.5 $ $Date: 2008/06/15 19:07:27 $
* @param
* <P>
* 解码器返回的数据包内容
*/
public abstract class AbstractPacketDecoder<P> extends MessageDecoderAdapter {

/**
* 每个数据包头的默认长度:3字节(1位标志位+2位长度位)。
* 个别标志位下4位长度位或者没有长度位的情况下,请覆盖@{code retrieveHeaderLength()}方法。
* @see #retrieveHeaderLength()
*/
public static final int DEFAULT_HEADER_LENGTH = 3;

/**
* 日志对象
*/
protected final Log log = LogFactory.getLog(getClass());

/**
* 数据包类型
*/
protected byte type;

/**
* 创建一个新的<code>AbstractPacketDecoder</code>对象。
*
* @param type
* 可以解码的数据类型
*/
protected AbstractPacketDecoder(byte type) {
this.type = type;
}

/**
* 判断当前解码器能否解码最新读入的数据。
*
* @param session
* 连接会话
* @param in
* 读入的字节缓冲
* @return 是否可解码: {@code MessageDecoder.OK} 可以解码;
* {@code MessageDecoder.NOT_OK} 不能解码;
* {@code MessageDecoder.NEED_DATA} 需要更多数据才能判断是否能够解码
* @see org.apache.mina.filter.codec.demux.MessageDecoder#decodable(org.apache.mina.common.IoSession,
* org.apache.mina.common.ByteBuffer)
*/
public MessageDecoderResult decodable(IoSession session, ByteBuffer in) {
// 数据包头长度
int headerLength = retrieveHeaderLength();
if (in.remaining() < headerLength) {
// 读入的字节缓冲中的剩余数据长度小于数据包头长度,需要更多数据
// 注意:即使有标志位便可以确认当前类能否解码,仍然需要确保第一次解码时能够正确读入长度数据
return NEED_DATA;
}

// 数据包类型
byte contentType = in.get();
if (contentType == type) {
// 数据包类型与当前解码器可以解码的数据类型匹配,可以解码
return OK;
} else {
// 数据包类型与当前解码器可以解码的数据类型匹配,不能解码
return NOT_OK;
}
}

/**
* 解码最新读入的数据。
*
* @param session
* 会话连接
* @param in
* 读入的字节缓冲
* @param out
* 存放解码结果的输出
* @return 处理结果: {@code MessageDecoder.OK} 可以解码; {@code MessageDecoder.NOT_OK}
* 不能解码; {@code MessageDecoder.NEED_DATA} 需要更多数据才能判断是否能够解码
* @throws Exception
* 如果在处理中发生异常的话
* @see org.apache.mina.filter.codec.demux.MessageDecoder#decode(org.apache.mina.common.IoSession,
* org.apache.mina.common.ByteBuffer,
* org.apache.mina.filter.codec.ProtocolDecoderOutput)
*/
public MessageDecoderResult decode(IoSession session,
ByteBuffer in,
ProtocolDecoderOutput out)
throws Exception {
// 记录原有位置
in.mark();
// 跳过数据包标志位
in.get();
// 数据包长度
int contentLength = getContentLength(session, in);

if (in.remaining() < contentLength) {
// 当前物理数据包长度小于逻辑数据包长度,重置开始位置
in.position(in.markValue());
// 需要更多数据
return NEED_DATA;
}

// 解码数据体
P packet = decodeBody(session, in, contentLength);
if (packet == null) {
// 错误
return NOT_OK;
}

// 保存数据包对象
out.write(packet);
// 解码成功
return OK;
}

/**
* 返回数据包头的长度。
* <p>
* 针对个别包4位长度位或者没有长度位的情况,子类应该覆盖该方法,返回对应的数据包头长度。
* </p>
*
* @return 数据包头的长度
*/
protected int retrieveHeaderLength() {
return DEFAULT_HEADER_LENGTH;
}

/**
* 获取数据体(不含标志位及长度位本身)的字节长度。
* <p>
* 本方法会在获取数据包类型后被调用,默认从当前字节缓冲中读取2字节长度信息。
* </p>
* <p>
* 子类可以覆盖该方法,直接返回长度信息而不从字节缓冲中读取。
* </p>
*
* @param session
* 会话连接
* @param in
* 字节缓冲
* @return 数据体长度,它可以是:
* <ul>
* <li>从数据包中特定位置读取的长度信息</li>
* <li><code>NEED_MORE_LENGTH_INFO</code>代表需要更多字节才能判断长度</li>
* </ul>
*/
protected int getContentLength(IoSession session, ByteBuffer in) {
return in.getShort();
}

/**
* 解码数据体内容,并返回对应的数据对象。
*
* @param session
* 会话连接
* @param in
* 读入的字节缓冲
* @param contentLength
* 数据体长度
* @return 数据体内容解码后得到的对应的数据对象,或者 <code>null</code> 代表解码时发生错误。
* @throws Exception
* 如果在处理中发生异常的话
*/
protected abstract P decodeBody(IoSession session,
ByteBuffer in,
int contentLength) throws Exception;
}

50,528

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧