成帧的方式
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;
}
}