【前言】接手了一个新项目,要对接一个很大的“结构体”,传输协议是Http,载荷打算用protocol buff封装。为了让结构更轻,继续用了Netty框架,那么现在的问题就是:如何在Netty上基于Http协议来接收protocol buff。本系列第三篇是基于TCP方式使用protocol buff
【发送端】发送端依然使用java,虽然是Http,但是我们直接发送字节数组,关键点在Content-Type的设置。以URLConnection为例
private String address;
private BufferedWriter writer = null;
private BufferedReader reader = null;
private JSONObject jObject = null;
public HttpPost(String address) {
this.address = address;
}
public String sendBytes(byte[] bytes) {
String line = null;
StringBuilder sb = new StringBuilder();
try {
URL url = new URL(address);
URLConnection conn = url.openConnection();
conn.setUseCaches(false); //不用缓存
//设置超时时间
conn.setConnectTimeout(new Integer(Property.getProperty("connectTimeout")).intValue());
conn.setReadTimeout(new Integer(Property.getProperty("readTimeout")).intValue());
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "myServer");
conn.setRequestProperty("Content-Type", "application/octet-stream;charset=utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
writer = new BufferedWriter(new PrintWriter(conn.getOutputStream()));
writer.write(new String(bytes));
writer.flush();
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch(Exception e) {
} finally {
try{
if(writer!=null){
writer.close();
}
if(reader!=null){
reader.close();
}
}
catch(IOException ex){
}
}
return sb.toString();
}
有了HTTP发送端之后,再看下protocol buff获取byte[] 的方法:
比如有一个 MyProtocolBuff 的 对象 buff,用.toByteArray()方法就可以得到buff对象对应的byte[]
调用 sendBytes(buff.toByteArray()); 就能在Http中把buff发出去了。
【接收端】接收端要在处理Http协议的handler中处理代码,比如我实现了一个HTTPHandler
public class HTTPHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
//消息体
ByteBuf buff = request.content();
}
ByteBuf buff = request.content(); 就得到一个Netty专属ByteBuf(底层buf,当实现了SimpleChannelInboundHandler接口后,在channelRead0方法调用完成后会自动释放,原理是 SimpleChannelInboundHandler中的autoRelease标记 )。我们拿到ByteBuf后,需要用特别的方式从它内部存储结构中获取byte[]数组:
int length = buff.writerIndex() - buff.readerIndex();
byte[] bytes = new byte[length]; // 传入的Byte数据
buff.getBytes(buff.readerIndex(), bytes);
最后我们用bytes在接收端恢复
MyProtocolBuff对象
MyProtocolBuff receivedBuff = MyProtocolBuff.parseFrom(bytes);
即可。