客户端发起一个文本请求给服务器端, 服务器端解析里面文本, 返回文件给客户端, 客户端解析文件
因为示例文件比较小, 所以没有做分段传输, 而是直接一次性把整个文件byte[]都发给客户端了.
如果需要传输大文件, 则需要做粘包拆包, 参考另外一篇博文 Netty之粘包分包
需要三个ChannelPipeline
1 // 解析客户端发送的文本json
2 pipeline.addLast(new StringDecoder());
3 // 二进制文件加密传输
4 pipeline.addLast(new ObjectEncoder());
5 // 业务逻辑
6 pipeline.addLast(new FileServerHandler());
FileServerHandler业务逻辑
// 获取到客户端请求, 解析path, 返回二进制文件
JSONObject jo = new JSONObject(msg.toString());
if (StringUtils.isNotEmpty(jo.optString("path"))) {
PDFContent pdf = new PDFContent();
byte[] content = com.fr.general.IOUtils.inputStream2Bytes(new FileInputStream(jo.optString("path")));
pdf.setContent(content);
ctx.writeAndFlush(pdf);
} else {
System.out.println(jo.optString("res"));
}
跟服务器端对应的三个ChannelPipeline
1 // 传输文本给服务器端
2 p.addLast(new StringEncoder());
3 // 二进制文件获取解析
4 p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this
5 .getClass().getClassLoader())));
6 // 客户端业务代码
7 p.addLast(new FileClientHandler());
FileClientHandler业务逻辑
1 @Override
2 public void channelActive(ChannelHandlerContext ctx) {
3 try {
4 // 将要获取的pdf路径发送给服务器端
5 JSONObject jo = JSONObject.create().put("path", "d:\\a.pdf");
6 ctx.writeAndFlush(jo.toString());
7 } catch (JSONException e) {
8 e.printStackTrace();
9 }
10 }
11
12 @Override
13 public void channelRead(ChannelHandlerContext ctx, Object msg) {
14 PDFContent content = (PDFContent) msg;
15 // 从服务器端获取的二进制文件存到本地
16 String fileName = UUID.randomUUID().toString() + ".pdf";
17 File file = new File("D:\\" + fileName);
18 try {
19 FileOutputStream out = new FileOutputStream(file);
20 IOUtils.copyBinaryTo(new ByteArrayInputStream(content.getContent()), out);
21 out.close();
22 } catch (FileNotFoundException e) {
23 e.printStackTrace();
24 } catch (IOException e) {
25 e.printStackTrace();
26 }
27 try {
28 JSONObject jo = JSONObject.create().put("res", "Thank You, I Have The File!");
29 ctx.writeAndFlush(jo.toString());
30 ctx.close();
31 } catch (JSONException e) {
32 e.printStackTrace();
33 }
34 }
完整的代码如下
FileClient & FileClientHandler
1 package test;
2
3 import com.fr.general.IOUtils;
4 import com.fr.json.JSONException;
5 import com.fr.json.JSONObject;
6 import com.fr.stable.core.UUID;
7 import io.netty.bootstrap.Bootstrap;
8 import io.netty.channel.ChannelFuture;
9 import io.netty.channel.ChannelHandlerContext;
10 import io.netty.channel.ChannelInboundHandlerAdapter;
11 import io.netty.channel.ChannelInitializer;
12 import io.netty.channel.ChannelPipeline;
13 import io.netty.channel.EventLoopGroup;
14 import io.netty.channel.nio.NioEventLoopGroup;
15 import io.netty.channel.socket.SocketChannel;
16 import io.netty.channel.socket.nio.NioSocketChannel;
17 import io.netty.handler.codec.serialization.ClassResolvers;
18 import io.netty.handler.codec.serialization.ObjectDecoder;
19 import io.netty.handler.codec.string.StringEncoder;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26
27 public class FileClient {
28
29 public FileClient(){
30
31 }
32
33 public void start() {
34 EventLoopGroup group = new NioEventLoopGroup();
35 try {
36 Bootstrap bootstrap = new Bootstrap();
37 bootstrap.group(group)
38 .channel(NioSocketChannel.class)
39 .handler(new ChannelInitializer<SocketChannel>() {
40
41 @Override
42 protected void initChannel(SocketChannel s) throws Exception {
43 ChannelPipeline p = s.pipeline();
44 // 传输文本给服务器端
45 p.addLast(new StringEncoder());
46 // 二进制文件获取解析
47 p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this
48 .getClass().getClassLoader())));
49 // 客户端业务代码
50 p.addLast(new FileClientHandler());
51 }
52 });
53 ChannelFuture future = bootstrap.connect("localhost", 7766).sync();
54 future.channel().closeFuture().sync();
55 } catch (InterruptedException e) {
56 e.printStackTrace();
57 } finally {
58 group.shutdownGracefully();
59 }
60 }
61
62 public static void main(String[] args) throws InterruptedException {
63 new FileClient().start();
64 }
65
66 private static class FileClientHandler extends ChannelInboundHandlerAdapter {
67
68
69 @Override
70 public void channelActive(ChannelHandlerContext ctx) {
71 try {
72 // 将要获取的pdf路径发送给服务器端
73 JSONObject jo = JSONObject.create().put("path", "d:\\a.pdf");
74 ctx.writeAndFlush(jo.toString());
75 } catch (JSONException e) {
76 e.printStackTrace();
77 }
78 }
79
80 @Override
81 public void channelRead(ChannelHandlerContext ctx, Object msg) {
82 PDFContent content = (PDFContent) msg;
83 // 从服务器端获取的二进制文件存到本地
84 String fileName = UUID.randomUUID().toString() + ".pdf";
85 File file = new File("D:\\" + fileName);
86 try {
87 FileOutputStream out = new FileOutputStream(file);
88 IOUtils.copyBinaryTo(new ByteArrayInputStream(content.getContent()), out);
89 out.close();
90 } catch (FileNotFoundException e) {
91 e.printStackTrace();
92 } catch (IOException e) {
93 e.printStackTrace();
94 }
95 try {
96 JSONObject jo = JSONObject.create().put("res", "Thank You, I Have The File!");
97 ctx.writeAndFlush(jo.toString());
98 ctx.close();
99 } catch (JSONException e) {
100 e.printStackTrace();
101 }
102 }
103
104 @Override
105 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
106 cause.printStackTrace();
107 ctx.close();
108 }
109 }
110 }
FileServer & FileServerHandler
1 package test;
2
3 import com.fr.json.JSONObject;
4 import com.fr.stable.StringUtils;
5 import io.netty.bootstrap.ServerBootstrap;
6 import io.netty.channel.ChannelFuture;
7 import io.netty.channel.ChannelHandlerContext;
8 import io.netty.channel.ChannelInboundHandlerAdapter;
9 import io.netty.channel.ChannelInitializer;
10 import io.netty.channel.ChannelOption;
11 import io.netty.channel.ChannelPipeline;
12 import io.netty.channel.EventLoopGroup;
13 import io.netty.channel.nio.NioEventLoopGroup;
14 import io.netty.channel.socket.SocketChannel;
15 import io.netty.channel.socket.nio.NioServerSocketChannel;
16 import io.netty.handler.codec.serialization.ObjectEncoder;
17 import io.netty.handler.codec.string.StringDecoder;
18 import io.netty.handler.logging.LogLevel;
19 import io.netty.handler.logging.LoggingHandler;
20
21 import java.io.FileInputStream;
22
23 public class FileServer {
24
25 private FileServer() {
26 startServer();
27 }
28
29 private void startServer() {
30 EventLoopGroup bossGroup = new NioEventLoopGroup(1);
31 EventLoopGroup workerGroup = new NioEventLoopGroup();
32 try{
33 ServerBootstrap bootstrap = new ServerBootstrap();
34 bootstrap.group(bossGroup, workerGroup)
35 .channel(NioServerSocketChannel.class)
36 .option(ChannelOption.SO_BACKLOG, 100)
37 .handler(new LoggingHandler(LogLevel.INFO))
38 .childHandler(new ChannelInitializer<SocketChannel>() {
39 @Override
40 protected void initChannel(SocketChannel ch) throws Exception {
41 ChannelPipeline pipeline = ch.pipeline();
42 // 解析客户端发送的文本json
43 pipeline.addLast(new StringDecoder());
44 // 二进制文件加密传输
45 pipeline.addLast(new ObjectEncoder());
46 // 业务逻辑
47 pipeline.addLast(new FileServerHandler());
48 }
49 });
50 ChannelFuture future = bootstrap.bind("localhost", 7766).sync();
51 future.channel().closeFuture().sync();
52 } catch (InterruptedException e) {
53 e.printStackTrace();
54 } finally {
55 bossGroup.shutdownGracefully();
56 workerGroup.shutdownGracefully();
57 }
58
59 }
60
61 private class FileServerHandler extends ChannelInboundHandlerAdapter {
62
63 @Override
64 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
65 // 获取到客户端请求, 解析path, 返回二进制文件
66 JSONObject jo = new JSONObject(msg.toString());
67 if (StringUtils.isNotEmpty(jo.optString("path"))) {
68 PDFContent pdf = new PDFContent();
69 byte[] content = com.fr.general.IOUtils.inputStream2Bytes(new FileInputStream(jo.optString("path")));
70 pdf.setContent(content);
71 ctx.writeAndFlush(pdf);
72 } else {
73 System.out.println(jo.optString("res"));
74 }
75 }
76
77 @Override
78 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
79 cause.printStackTrace();
80 ctx.close();
81 }
82 }
83
84 public static void main(String[] args){
85 // 启动Server
86 new FileServer();
87 }
88
89
90 }
PDFContent
1 package test;
2
3 import java.io.Serializable;
4
5 /**
6 * 文件的封装
7 */
8 public class PDFContent implements Serializable{
9
10 private byte[] content;
11
12 public byte[] getContent() {
13 return content;
14 }
15
16 public void setContent(byte[] content) {
17 this.content = content;
18 }
19 }