代码
maven
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.5.Final</version>
</dependency>
加解密
package com.ydfind.tool.transfer;
import java.io.UnsupportedEncodingException;
public class EncryptUt {
public static byte[] decrypt(byte[] data) {
if (null == data || data.length == 0) {
return data;
}
for (int i = 0; i < data.length; i++) {
data[i] = data[i] == Byte.MIN_VALUE ? Byte.MIN_VALUE : --data[i];
}
return data;
}
public static String decrypt(String name) throws UnsupportedEncodingException {
if (null == name || name.length() == 0) {
return name;
}
byte[] data = name.getBytes("utf-8");
return new String(decrypt(data));
}
public static byte[] encrypt(byte[] data, int len) {
if (null == data || data.length == 0) {
return data;
}
byte[] result = new byte[len];
for (int i = 0; i < len; i++) {
result[i] = (data[i] == Byte.MAX_VALUE) ? Byte.MIN_VALUE : (++data[i]);
}
return result;
}
public static String encrypt(String name) {
if (null == name || name.length() == 0) {
return name;
}
byte[] data = name.getBytes(StandardCharsets.UTF_8);
data = encrypt(data, data.length);
return new String(data);
}
}
服务端
package com.ydfind.tool.transfer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FileUploadServer {
public static void main(String[] args) {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
try {
bind(port);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void bind(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ObjectEncoder());
ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE,
ClassResolvers.weakCachingConcurrentResolver(null)));
ch.pipeline().addLast(new FileEncryptUploadHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static class FileEncryptUploadHandler extends ChannelInboundHandlerAdapter {
private volatile int start = 0;
private String file_dir = "/Users/deng/YDTotal/";
RandomAccessFile randomAccessFile;
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelRegistered();
System.out.println("注册");
}
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelUnregistered();
System.out.println("注销");
}
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelWritabilityChanged();
System.out.println("可读状态变更:" + ctx.channel().isWritable());
}
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
System.out.println("激活");
}
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelInactive();
System.out.println("断开");
}
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelReadComplete();
System.out.println("读取完成");
}
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
ctx.fireUserEventTriggered(evt);
System.out.println("用户事件");
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("发生异常");
cause.printStackTrace();
ctx.fireExceptionCaught(cause);
ctx.close();
releaseFile();
}
public void initFile(String name) throws IOException {
String path = file_dir + name;
File file = new File(path);
randomAccessFile = new RandomAccessFile(file, "rw");
randomAccessFile.seek(start);
}
public void releaseFile() {
if (randomAccessFile != null) {
try {
randomAccessFile.close();
System.out.println("本地文件释放成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("读取消息------");
if (msg instanceof String) {
initFile(EncryptUt.decrypt((String)msg));
// 通知对方从0开始读取
ctx.writeAndFlush(0);
} else if (msg instanceof byte[]) {
byte[] data = (byte[])msg;
randomAccessFile.write(EncryptUt.decrypt(data));
start = start + data.length;
if (data.length > 0) {
// 通知对方 从start开始读取
ctx.writeAndFlush(start);
} else {
releaseFile();
ctx.close();
}
}
}
}
}
客户端
package com.ydfind.tool.transfer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
public class FileUploadClient {
public static void main(String[] args) {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
try {
String filename = "/Users/admin/YDTotal/test.txt";
File file = new File(filename);
connect(port, "192.168.0.101", file);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void connect(int port, String host, final File file) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ObjectEncoder());
ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(null)));
ch.pipeline().addLast(new FileEncryptUploadClientHandler(file));
}
});
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
public static class FileEncryptUploadClientHandler extends ChannelInboundHandlerAdapter {
public RandomAccessFile randomAccessFile;
public RandomAccessFile backFile;
public File dataFile;
public FileEncryptUploadClientHandler(File dataFile) {
if (dataFile.exists() && !dataFile.isFile()) {
System.out.println("文件不存在 :" + dataFile.getPath());
return;
}
this.dataFile = dataFile;
}
public void channelActive(ChannelHandlerContext ctx) {
try {
randomAccessFile = new RandomAccessFile(dataFile, "r");
randomAccessFile.seek(0);
System.out.println("文件创建成功,name=" + dataFile.getName());
String data = EncryptUt.encrypt(dataFile.getName());
ctx.writeAndFlush(data);
backFile = new RandomAccessFile(new File(dataFile.getPath() + ".back"), "rw");
backFile.seek(0);
backFile.write(data.getBytes("utf-8"));
backFile.write("\n".getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Integer) {
Integer start = (Integer) msg;
if (start != -1) {
randomAccessFile.seek(start);
System.out.println("总长度" + randomAccessFile.length() + ", 剩余长度:" + (randomAccessFile.length() - start));
int a = (int) (randomAccessFile.length() - start);
int lastLength = Math.min(a, 1024);
byte[] bytes = new byte[lastLength];
int byteRead;
if ((byteRead = randomAccessFile.read(bytes)) != -1 && (randomAccessFile.length() - start) > 0) {
try {
byte[] data = EncryptUt.encrypt(bytes, byteRead);
ctx.writeAndFlush(data);
backFile.write(data);
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
ctx.writeAndFlush(new byte[0]);
} catch (Exception e) {
e.printStackTrace();
}
randomAccessFile.close();
backFile.close();
ctx.close();
System.out.println("file读取完成.");
}
}
}
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
}
测试
先启动服务端,再运行客户端,会发现 客户端的文件 会 加密传输到 服务端 指定目录下: