Netty之文件传输

来源:互联网 发布:平面设计网络兼职 编辑:程序博客网 时间:2024/05/16 05:41

1、工程的目录结构

   

2、GZIP进行压缩和解压的工具类

import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.util.zip.GZIPInputStream;import java.util.zip.GZIPOutputStream;public class GzipUtils {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;}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;}public static void main(String[] args) throws Exception {// 读取文件String readPath = System.getProperty("user.dir") + File.separatorChar+ "sources" + File.separatorChar + "005.jpg";File file = new File(readPath);FileInputStream in = new FileInputStream(file);byte[] data = new byte[in.available()];in.read(data);in.close();System.out.println("文件原始大小:" + data.length);// 测试压缩byte[] ret1 = GzipUtils.gzip(data);System.out.println("压缩之后大小:" + ret1.length);// 还原文件byte[] ret2 = GzipUtils.ungzip(ret1);System.out.println("还原之后大小:" + ret2.length);// 写出文件String writePath = System.getProperty("user.dir") + File.separatorChar+ "receive" + File.separatorChar + "005.jpg";FileOutputStream fos = new FileOutputStream(writePath);fos.write(ret2);fos.close();}}
3、在客户端的请求Request中,加入要传输的文件(private byte[] attachment)

import java.io.Serializable;public class Request implements Serializable {/** *  */private static final long serialVersionUID = -2813211330451521507L;private String id;private String name;private String requestMessage;private byte[] attachment;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRequestMessage() {return requestMessage;}public void setRequestMessage(String requestMessage) {this.requestMessage = requestMessage;}public byte[] getAttachment() {return attachment;}public void setAttachment(byte[] attachment) {this.attachment = attachment;}}
4、服务端的Response

import java.io.Serializable;public class Response implements Serializable {/** *  */private static final long serialVersionUID = -5640678664176009458L;private String id;private String name;private String responseMessage;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getResponseMessage() {return responseMessage;}public void setResponseMessage(String responseMessage) {this.responseMessage = responseMessage;}@Overridepublic String toString() {return "Response [id=" + id + ", name=" + name + ", responseMessage="+ responseMessage + "]";}}
5、Jboss序列化工具

import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;import io.netty.handler.codec.marshalling.MarshallerProvider;import io.netty.handler.codec.marshalling.MarshallingDecoder;import io.netty.handler.codec.marshalling.MarshallingEncoder;import io.netty.handler.codec.marshalling.UnmarshallerProvider;import org.jboss.marshalling.MarshallerFactory;import org.jboss.marshalling.Marshalling;import org.jboss.marshalling.MarshallingConfiguration;/** * Marshalling工厂 *  */public final class MarshallingCodeCFactory {/** * 创建Jboss Marshalling解码器MarshallingDecoder *  * @return MarshallingDecoder */public static MarshallingDecoder buildMarshallingDecoder() {// 首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");// 创建了MarshallingConfiguration对象,配置了版本号为5final MarshallingConfiguration configuration = new MarshallingConfiguration();configuration.setVersion(5);// 根据marshallerFactory和configuration创建providerUnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);// 构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度MarshallingDecoder decoder = new MarshallingDecoder(provider,1024 * 1024 * 1);return decoder;}/** * 创建Jboss Marshalling编码器MarshallingEncoder *  * @return MarshallingEncoder */public static MarshallingEncoder buildMarshallingEncoder() {final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");final MarshallingConfiguration configuration = new MarshallingConfiguration();configuration.setVersion(5);MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);// 构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组MarshallingEncoder encoder = new MarshallingEncoder(provider);return encoder;}}
6、服务端的实现

import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.logging.LogLevel;import io.netty.handler.logging.LoggingHandler;public class Server {public Server() {}public void bind(int port) throws Exception {// 配置NIO线程组EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {// 服务器辅助启动类配置ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChildChannelHandler())//.option(ChannelOption.SO_BACKLOG, 1024) // 设置tcp缓冲区 // (5).childOption(ChannelOption.SO_KEEPALIVE, true); // (6)// 绑定端口 同步等待绑定成功ChannelFuture f = b.bind(port).sync(); // (7)// 等到服务端监听端口关闭f.channel().closeFuture().sync();} finally {// 优雅释放线程资源workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}/** * 网络事件处理器 */private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// 添加Jboss的序列化,编解码工具ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());// 处理网络IOch.pipeline().addLast(new ServerHandler());}}public static void main(String[] args) throws Exception {new Server().bind(9999);}}
7、服务端的Handler的实现

import java.io.File;import java.io.FileOutputStream;import com.netty.utils.GzipUtils;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;public class ServerHandler extends ChannelHandlerAdapter {// 用于获取客户端发送的信息@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {Request req = (Request) msg;System.out.println("Server : " + req.getId() + ", " + req.getName()+ ", " + req.getRequestMessage());// 进行图片资源的还原byte[] attachment = GzipUtils.ungzip(req.getAttachment());// 获取图片的保存目录String path = System.getProperty("user.dir") + File.separatorChar+ "receive" + File.separatorChar + req.getName();// 进行图片的保存FileOutputStream fos = new FileOutputStream(path);fos.write(attachment);fos.close();// 给客户端,响应数据Response resp = new Response();resp.setId(req.getId());resp.setName("resp" + req.getId());resp.setResponseMessage("响应内容" + req.getId());ctx.writeAndFlush(resp);// .addListener(ChannelFutureListener.CLOSE);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {// cause.printStackTrace();ctx.close();}}
8、客户端的实现

import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;public class Client {/** * 连接服务器 *  * @param port * @param host * @throws Exception */public void connect(int port, String host) throws Exception {// 配置客户端NIO线程组EventLoopGroup group = new NioEventLoopGroup();try {// 客户端辅助启动类 对客户端配置Bootstrap b = new Bootstrap();b.group(group)//.channel(NioSocketChannel.class)//.option(ChannelOption.TCP_NODELAY, true)//.handler(new MyChannelHandler());//// 异步链接服务器 同步等待链接成功ChannelFuture f = b.connect(host, port).sync();// 等待链接关闭f.channel().closeFuture().sync();} finally {group.shutdownGracefully();System.out.println("客户端优雅的释放了线程资源...");}}/** * 网络事件处理器 */private class MyChannelHandler extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// 添加Jboss的序列化,编解码工具ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());// 处理网络IOch.pipeline().addLast(new ClientHandler());// 处理网络IO}}public static void main(String[] args) throws Exception {new Client().connect(9999, "127.0.0.1");}}
9、客户端的Handler的实现

import java.io.File;import java.io.FileInputStream;import com.netty.utils.GzipUtils;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;import io.netty.util.ReferenceCountUtil;//用于读取客户端发来的信息public class ClientHandler extends ChannelHandlerAdapter {// 客户端与服务端,连接成功的售后@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {// 进行图片的传输for (int i = 0; i < 5; i++) {String fileName = "00" + (i + 1) + ".jpg";// 进行文件的读取String path = System.getProperty("user.dir") + File.separatorChar+ "sources" + File.separatorChar + fileName;File file = new File(path);Request req = new Request();req.setId("" + i);req.setName(file.getName());req.setRequestMessage("数据信息" + i);// 进行图片的读取FileInputStream in = new FileInputStream(file);byte[] data = new byte[in.available()];in.read(data);in.close();// 进行数据的压缩req.setAttachment(GzipUtils.gzip(data));// 向服务端,传送图片信息ctx.channel().writeAndFlush(req);}}// 只是读数据,没有写数据的话// 需要自己手动的释放的消息@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {try {Response response = (Response) msg;System.out.println(response);} finally {ReferenceCountUtil.release(msg);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.close();}}

1 0