步骤1:添加相关的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.12.Final</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling</artifactId>
<version>1.3.0.CR9</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-serial</artifactId>
<version>1.3.0.CR9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
步骤2:定义发送和接受数据实体
/**【发送数据实体】*/
import java.io.Serializable;
public class RequestData implements Serializable {
private static final long serialVersionUID = 7359175860641122157L;
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;}
}
/**【接受数据实体】*/
import java.io.Serializable;
public class ResponseData implements Serializable {
private static final long serialVersionUID = -6231852018644360658L;
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;}
}
步骤3: 创建Jboss Marshalling解码器MarshallingDecoder和编码器MarshallingEncoder
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;
public final class MarshallingCodeCFactory {
/**
* 创建Jboss Marshalling解码器MarshallingDecoder
* @return MarshallingDecoder
*/
public static MarshallingDecoder buildMarshallingDecoder() {
//首先通过Marshalling工具类的方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置了版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallerFactory和configuration创建provider
UnmarshallerProvider 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;
}
}
步骤4:创建解压缩字节数组工具类
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 {
//1.压缩字节数组
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;
}
//2.解压字节数据
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 + "006.jpg";
readPath ="F:\\001.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 + "006.jpg";
writePath = "F:\\001_cp.jpg";
FileOutputStream fos = new FileOutputStream(writePath);
fos.write(ret2);
fos.close();
}
}
步骤5:创建netty server端
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;
public class Server {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bGroup = new NioEventLoopGroup(1);
EventLoopGroup wGroup = new NioEventLoopGroup();
ServerBootstrap sb = new ServerBootstrap();
sb.group(bGroup, wGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder()); //解码器
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder()); //编码器
sc.pipeline().addLast(new ServerHandler()); //业务处理类
}
});
ChannelFuture cf = sb.bind(8765).sync();
cf.channel().closeFuture().sync();
bGroup.shutdownGracefully();
wGroup.shutdownGracefully();
}
}
步骤6:创建netty server端对应Handler处理类
import java.io.File;
import java.io.FileOutputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 接受request请求 并进行业务处理
RequestData rd = (RequestData)msg;
System.err.println("id: " + rd.getId() + ", name: " + rd.getName() + ", requestMessage: " + rd.getRequestMessage());
byte[] attachment = GzipUtils.ungzip(rd.getAttachment());
String path = System.getProperty("user.dir")+ File.separatorChar + "receive" + File.separatorChar + "001.jpg";
FileOutputStream fos = new FileOutputStream(path);
fos.write(attachment);
fos.close();
// 回送相应数据
ResponseData responseData = new ResponseData();
responseData.setId("response " + rd.getId());
responseData.setId("response " + rd.getName());
responseData.setResponseMessage("响应信息");
ctx.writeAndFlush(responseData);
}
}
步骤7:创建netty client端
import java.io.File;
import java.io.FileInputStream;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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;
public class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup wGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(wGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture cf = b.connect("127.0.0.1", 8765).sync();
Channel channel = cf.channel();
for(int i =0; i < 100; i++) {
RequestData rd = new RequestData();
rd.setId("" + i);
rd.setName("我是消息" + i);
rd.setRequestMessage("内容" + i);
String path = System.getProperty("user.dir")
+ File.separatorChar + "source" + File.separatorChar + "001.jpg";
File file = new File(path);
FileInputStream fis = new FileInputStream(file);
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
rd.setAttachment(GzipUtils.gzip(data));
channel.writeAndFlush(rd);
}
cf.channel().closeFuture().sync();
wGroup.shutdownGracefully();
}
}
步骤8:创建netty client端对应Handler处理类
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
public class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
ResponseData rd = (ResponseData)msg;
System.err.println("输出服务器端相应内容: " + rd.getId());
} finally {
ReferenceCountUtil.release(msg); //一定要释放资源
}
}
}
原理图: