成帧的方式
1.基于定界符(Delimiter-based)
2.显式长度(Explicit length)
接口:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Framer接口。 * frameMsg()方法用来添加成帧信息并将指定消息输出到指定流 * nextMsg()方法则扫描指定的流,从中抽取出下一条消息。 * @authorLyn * */ publicinterface IFramer { void frameMsg(byte[] message,OutputStream out) throws IOException; byte[] nextMsg(InputStream in)throws IOException; }
基于定界符(Delimiter-based)的实现
import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * 基于分界符的Framer * @author Lyn * */ public class DelimiterFramerimplements IFramer { privatestaticfinalbyteDELIMITER = '\n'; @Override public void frameMsg(byte[] message, OutputStream out) throws IOException { for(byte b : message){ if(b ==DELIMITER){ thrownew IOException("不能生成一帧,数据里含有定界符"); } } out.write(message); out.write(DELIMITER); out.flush(); } @Override public byte[] nextMsg(InputStream in)throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int nextByte; while( (nextByte=in.read()) !=DELIMITER){ //最后一个,但不是定界符 if(nextByte == -1){ if(baos.size() == 0){ return null; }else{ thrownew EOFException("成帧失败:数据已读完,但最后不是定界符"); } } baos.write(nextByte); } return baos.toByteArray(); } }
显式长度(Explicit length)的实现
import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * 显式长度帧Framer * @author Lyn */ public class ExplicitLengthFramerimplements IFramer { public staticfinalintMAX_MESSAGE_LENGTH = 65535; public staticfinalintBYTE_MASK = 0xff; public staticfinalintBYTE_SHIFT = 8; @Override public void frameMsg(byte[] message, OutputStream out) throws IOException { if(message.length >MAX_MESSAGE_LENGTH){ thrownew IOException("帧长度太长了,必须小于"+MAX_MESSAGE_LENGTH); } int length = message.length; //只写入一个int的低16位 out.write( (length>>BYTE_SHIFT) &BYTE_MASK );//写入 长度从左到右的第三个字节 out.write( length & BYTE_MASK ); //写入 长度从左到右的第四个字节 out.write(message); out.flush(); } @Override public byte[] nextMsg(InputStream in)throws IOException { DataInputStream dis = new DataInputStream(in); int length; try { //方法读取两个字节,将它们作为big-endian整数进行解释,并以int型整数返回它们的值。 length = dis.readUnsignedShort(); } catch (Exception e) { return null; } byte[] buf =newbyte[length]; dis.readFully(buf);//将阻塞等待,直到接收到足够的字节来填满指定的数组 return buf; } }