博客概述
本博客中的代码将使用java自带的压缩技术gzip对文件进行压缩,然后通过Marshalling框架对文件进行发送。需要注意的是Marshalling解码器在发送文件的场景,长度需要设置的大一些。本案例是在上一个案例基础上进行的,此处只给出变动的代码。
压缩帮助类
package utils;
import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* @Auther: ;李泽
* @Date: 2019/3/12 20:05
* @Description:
*/
public class GzipsUtils {
/**
* 功能描述: 数据压缩函数
*
* @auther: 李泽
* @date: 2019/3/12 20:09
*/
public static byte[] gzip(byte[] data) throws Exception{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
gzipOutputStream.write(data);
gzipOutputStream.finish();
gzipOutputStream.close();
byte[] bytes = outputStream.toByteArray();
outputStream.close();
return bytes;
}
/**
* 功能描述: 数据解压缩
*
* @auther: 李泽
* @date: 2019/3/12 22:42
*/
public static byte[] unzip(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;
}
/**
* 功能描述: 测试
*
* @auther: 李泽
* @date: 2019/3/12 22:48
*/
public static void main(String[] args) throws Exception {
//读取文件
String readPath =System.getProperty("user.dir")+ File.separatorChar+"sources"+ File.separatorChar+"006.jpg";
File file = new File(readPath);
FileInputStream fis = new FileInputStream(file);
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
System.out.println("文件原生大小"+data.length);
//测试压缩
byte[] ret1 = GzipsUtils.gzip(data);
System.out.println("文件压缩后大小"+ret1.length);
//还原
byte[] ret2 = GzipsUtils.unzip(ret1);
System.out.println("文件还原后大小"+ret2.length);
//写出文件
String writePath =System.getProperty("user.dir")+ File.separatorChar+"receive"+ File.separatorChar+"006.jpg";
FileOutputStream fos = new FileOutputStream(writePath);
fos.write(ret2);
fos.close();
}
}
客户端
package marshalling;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import utils.GzipsUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* @Auther: ;李泽
* @Date: 2019/3/4 22:05
* @Description:
*/
public class NettyClient {
public static void main(String[] args) throws Exception {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//设置Marshalling解编码器。
socketChannel.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
socketChannel.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
//这里面的是接受服务器端反馈时,才会触发的handler
socketChannel.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture channelFuture1 = bootstrap.connect("127.0.0.1",8080).sync();
//客户端发送数据,因为用了解编码框架
for (int i = 0; i < 5; i++) {
Request request = new Request();
request.setId(i+"");
request.setName("item"+i);
request.setRequestMessage("i am msg"+i);
String readPath =System.getProperty("user.dir")+ File.separatorChar+"sources"+ File.separatorChar+"006.jpg";
File file = new File(readPath);
FileInputStream fis = new FileInputStream(file);
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
request.setAttachment(GzipsUtils.gzip(data));
channelFuture1.channel().writeAndFlush(request);
}
//可以理解为阻塞在这
channelFuture1.channel().closeFuture().sync();
eventLoopGroup.shutdownGracefully();
}
}
服务端handler
package marshalling;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
import utils.GzipsUtils;
import java.io.File;
import java.io.FileOutputStream;
/**
* @Auther: ;李泽
* @Date: 2019/3/4 22:05
* @Description: 继承自ChannelHandlerAdapter,这个类实现了ChannelHandler接口,ChannelHandler提供了许多事件处理
* 的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承ChannelHandlerAdapter类而不是你自己去实
* 现接口方法。
*/
public class ServerHandler extends ChannelHandlerAdapter {
/**
* 功能描述: exceptionCaught()事件处理方法是当出现Throwable对象才会被调用,即当Netty由于IO错误或者处理器在处理事件
* 时抛出的异常时。在大部分情况下,捕获的异常应该被记录下来并且把关联的channel给关闭掉。然而这个方法的处
* 理方式会在遇到不同异常的情况下有不同的实现,比如你可能想在关闭连接之前发送一个错误码的响应消息。
*
* @auther: 李泽
* @date: 2019/3/4 22:24
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
/**
* 功能描述: 这里我们覆盖了chanelRead()事件处理方法。每当从客户端收到新的数据时,这个方法会在收到消息时被调用,
* 这个例子中,收到的消息的类型是Request,因为我们使用了解编码框架
*
* @auther: 李泽
* @date: 2019/3/4 22:23
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收数据
Request request = (Request) msg;
System.out.println("request = " + request);
String writePath =System.getProperty("user.dir")+ File.separatorChar+"receive"+ File.separatorChar+"006.jpg";
FileOutputStream fos = new FileOutputStream(writePath);
fos.write(GzipsUtils.unzip(request.getAttachment()));
fos.close();
//回写数据
Response response = new Response();
response.setId(request.getId());
response.setName("resp "+request.getName());
response.setResponseMessage("resp "+request.getRequestMessage());
ctx.writeAndFlush(response);
}
}