前段时间在工作中碰到了这个需求,以前没这样使用过netty,索性整理出来分享一下:
1.首先是创建http协议下的netty服务端
public class HttpGzipServer {
private static final Logger LOG = Logger.getLogger(HttpGzipServer.class);
private final int port;
private static boolean isSSL;
public HttpGzipServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new HttpGzipServerInitializer());
Channel ch = b.bind(port).sync().channel();
System.out.println("HTTP Upload Server at port " + port + '.');
System.err.println("Open your browser and navigate to http://localhost:" + port + '/');
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 9480;
}
if (args.length > 1) {
isSSL = true;
}
/**
* 启动netty服务器
*/
LOG.info("开始启动netty服务器");
new HttpGzipServer(port).run();
LOG.info("netty服务器启动成功");
}
2.渠道的初始化配置(主要是配置decompressor和codec这两个编解码器)
public class HttpGzipServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = ch.pipeline();
//服务端的gizp压缩应在request请求之前
pipeline.addLast("decompressor", new HttpContentCompressor());
pipeline.addLast("codec", new HttpServerCodec()); //3
pipeline.addLast("aggegator", new HttpObjectAggregator(512 * 1024));
pipeline.addLast("handler", new HttpGzipServerHandler());
/**
* http-request解码器
* http服务器端对request解码
*/
pipeline.addLast("decoder", new HttpRequestDecoder());
/**
* http-response解码器
* http服务器端对response编码
*/
pipeline.addLast("encoder", new HttpResponseEncoder());
/**
* 压缩
* Compresses an HttpMessage and an HttpContent in gzip or deflate encoding
* while respecting the "Accept-Encoding" header.
* If there is no matching encoding, no compression is done.
*/
/*pipeline.addLast("deflater", new HttpContentCompressor()); */
}
}
3.接下来是netty处理器的代码
public class HttpGzipServerHandler extends SimpleChannelInboundHandler<HttpObject> {
private static final Logger LOG = Logger.getLogger(HttpGzipServerHandler.class);
private HttpRequest request;
private HttpMethod method = null;
private final StringBuilder responseContent = new StringBuilder();
private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk
private HttpPostRequestDecoder decoder;
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
if (decoder != null) {
decoder.cleanFiles();
}
}
private void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
LOG.info(msg.getClass().getName());
if (msg instanceof HttpRequest) {
HttpRequest request = this.request = (HttpRequest) msg;
URI uri = new URI(request.getUri());
System.err.println("request uri==" + uri.getPath());
method = request.getMethod();
if (HttpMethod.POST.equals(method)) {
LOG.info("收到POST请求");
} else {
String responseString = "{\"code\":\"000001\"}";
LOG.info("收到GET请求");
writeHttpResponse(responseString, ctx, OK);
}
}
//2 msg是HttpContent
if (!HttpMethod.GET.equals(method)) {
if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf buf = content.content();
//从HttpContent拿到gzip数据流
并通过content方法拿到ByteBuf对象
try {
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
String body = GzipUtils.uncompress(bytes);
//通过gzip解压缩,拿到还原的json串数据
LOG.info("接收到数据:" + body);
/**
* 将数据发送到kafka服务器
*/
LOG.info("向kafka服务器发送消息");
long begin = System.currentTimeMillis();
KafkaProducer.commit(body);
long end = System.currentTimeMillis();
LOG.info("向kafka发送消息完成");
LOG.info("发送共耗时:"+(end-begin));
} catch (Exception e) {
LOG.error("", e);
}
buf.release();
writeHttpResponse("post返回成功!", ctx, OK);
}
}
}
4.gzipUtil工具类
public class GzipUtils {
/**
* gzip加密
* @param data
* @return
* @throws Exception
* byte[]
*/
public static byte[] gzip(byte[] data) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(bos);
gzip.write(data);
gzip.finish();
gzip.close();
byte[] ret = bos.toByteArray();
bos.close();
return ret;
}
/**
* gzip解密
* @param data
* @return
* @throws Exception
* byte[]
*/
public static byte[] ungzip(byte[] data) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
GZIPInputStream gzip = new GZIPInputStream(bis);
byte[] buf = new byte[1024];
int num = -1;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((num = gzip.read(buf, 0, buf.length)) != -1) {
bos.write(buf, 0, num);
}
gzip.close();
bis.close();
byte[] ret = bos.toByteArray();
bos.flush();
bos.close();
return ret;
}
/**
* gizp数据解压
* @param bytes
* @return
* @throws IOException
* String
*/
public static String uncompress(byte[] bytes) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
GZIPInputStream gunzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = gunzip.read(buffer))>= 0) {
out.write(buffer, 0, n);
}
// toString()使用平台默认编码,也可以显式的指定如toString("GBK")
return out.toString();
}
/**
* gizp解压
* @param buf
* @return
* @throws IOException
* byte[]
*/
public static byte[] unGzip(byte[] buf) throws IOException {
GZIPInputStream gzi = null;
ByteArrayOutputStream bos = null;
try {
gzi = new GZIPInputStream(new ByteArrayInputStream(buf));
bos = new ByteArrayOutputStream(buf.length);
int count = 0;
byte[] tmp = new byte[2048];
while ((count = gzi.read(tmp)) != -1) {
bos.write(tmp, 0, count);
}
buf = bos.toByteArray();
} finally {
if (bos != null) {
bos.flush();
bos.close();
}
if (gzi != null)
gzi.close();
}
return buf;
}
}
5.httpclient消息发送端
public class MessageSender {
public static void main(String[] args) {
httpMessageSend();
}
public static void httpMessageSend(){
String message = "{'name':'小徐','age':'25','sex':'男','height':'171'}";
try {
sendHttp("http://127.0.0.1:9480/v3/v3", message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* http发送util;
* @param String url byte[] data
*/
//gzip 压缩发送
public static void sendHttp(String url, String message) throws ClientProtocolException, IOException {
PostMethod postMethod = new PostMethod(url);
postMethod.setContentChunked(true);
postMethod.addRequestHeader("Accept", "text/plain");
postMethod.setRequestHeader("Content-Encoding", "gzip");
postMethod.setRequestHeader("Transfer-Encoding", "chunked");
try {
ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(originalContent);
gzipOut.write(message.getBytes(Charset.forName("UTF-8")));
gzipOut.finish();
postMethod.setRequestEntity(new ByteArrayRequestEntity(originalContent
.toByteArray(), "text/plain; charset=utf-8"));
} catch (Exception e) {
e.printStackTrace();
}
int retry = 0;
do {
try {
HttpClient httpClient = new HttpClient();
int status = httpClient.executeMethod(postMethod);
if (HttpStatus.SC_OK == status) {
System.out.println("send http success, url=" + url
+ ", content=" + message);
return;
} else {
String rsp = postMethod.getResponseBodyAsString();
System.out.println("send http fail, status is: " + status
+ ", response is: " + rsp);
}
} catch (HttpException e) {
System.out.println("http exception when send http.");
} catch (IOException e) {
System.out.println("io exception when send http.");
} finally {
postMethod.releaseConnection();
}
System.out.println("this is "+ retry + " time, try next");
} while (retry++ < 3);
}
}