netty是对socket的封装,底下走的TCP还是老一套,太大的HTTP包发送的时候是要被切分成好几段的,发送之后接收就变得很麻烦。网上有人提出多种解决方式,我自己试了试,结果如下:
1.对于HttpRequest,有人提出在头部协商消息体长度。不要轻易相信呐,骚年们,这玩意儿就是一个坑,写上之后那个不睁眼的TCP照样剁碎了给发出去!此处红色警戒!
2.不用TCP剁碎了,自己剁碎了传过去。此方是否对症,没试验。
3.定长消息。自我感觉不适合HttpRequest及HttpReponse这类东西,所以没试。
4.其他,如设置发送缓冲和接收缓冲等,均不管用
所以,从几个坑里面爬出来之后,我隆重推出netty的解决方案:用HttpObjectAggregator!!!
首先,在客户端和服务端的channel下的pipeline启动之前加上
<span style="white-space:pre"> </span>ch.pipeline().addLast("aggregator", new HttpObjectAggregator(1024*1024*64));
ch.pipeline().addLast("chunkedWriter", new ChunkedWriteHandler());
接收的时候就这样:
/**
* 读取传过来的消息,read request message from channel
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
if (msg instanceof DefaultHttpRequest) {
request = (DefaultHttpRequest) msg;
}
if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf buf = content.content();
messageOfClient = buf.toString(io.netty.util.CharsetUtil.UTF_8);
if(messageOfClient!=null&&!messageOfClient.contentEquals("")&&!messageOfClient.contains("ping")){
messageToSend+= messageOfClient;
}else{
System.out.println("channel的数目:"+ServerDataSyncServer.channels.size()+" channelGroupSize");
System.out.println(ctx.channel().remoteAddress().toString());
}
buf.release();
if(content instanceof LastHttpContent){
//此处对其他客户端的心跳包不予处理,因为服务端掉线之后会客户端会循环侦测连接,客户端断掉之后将服务端将不打印输出信息
if(messageToSend.length()>12&&messageToSend.substring(0, 2).contentEquals("DB")){
//消息长度符合一定条件,则是需要向其他客户端发送的数据库消息,调用方法转发
System.out.println("Server已读取数据库持久化信息,将开始向所有客户端发送");
ServerDataSyncServer.channels.remove(ctx.channel());
System.out.println("messageToSend "+messageToSend );
String messageContent = messageToSend;
ServerDataSyncServerSendGroup.sendToAllChannel(messageContent);
messageToSend = "";
}
}
}
}
当然,我的发送客户端是短连接,
ServerDataSyncServer.channels.remove(ctx.channel());
长连接的对这句可以直接忽略。
这样就可以了,netty接收到分段的大TCP包之后会自动组装成完整的HTTPrequest或者HttpResponse,然后逐个读取分段的消息体,最后一个是LastHttpContent类型,读到这个就算是整个包读完了,再做后续处理即可。
完毕