当前位置:编程学习 > JAVA >>

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

mina 在发送长报文时,为什么被截成好几段呢。请大侠帮帮忙。 --------------------编程问答-------------------- 这个是必然的。物理限制,和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;
}
--------------------编程问答-------------------- --------------------编程问答-------------------- 能不能把你的mina1的例子发给我看看,邮箱xmt1990@126.com
补充:Java ,  Java相关
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,