package com.lefu.remote.netty.test.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.nio.ByteBuffer;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.concurrent.GenericFutureListener;
import com.lefu.remote.netty.ChannelHandlerFactoryAdapter;
import com.lefu.remote.netty.client.IOConnector;
import com.lefu.remote.netty.client.NettyClient;
public class FileClient {
private NettyClient connector;
public FileClient() {
connector = new IOConnector(new FileClientHandlerFactory());
try {
connector.init();
} catch (Exception e) {
e.printStackTrace();
}
}
public Channel getChannel() throws Exception {
return connector.connect("192.168.14.9", 9999);
}
/**
* 文件传输协议头
* <pre>
* HeaderLen HeaderContent StreamLen Stream SHA
* 4(int) + N(byte[]) + 8(long) + M(byte[]) + 40(String)
* </pre>
* @param path
* @param param
* @param channel
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public void sendFile(String path, Object param, final Channel channel) throws NoSuchAlgorithmException, IOException {
final File f = new File(path);
System.out.println("File length: " + f.length());
final MessageDigest digest = MessageDigest.getInstance("SHA");
final InputStream in = new DigestInputStream(new BufferedInputStream(new FileInputStream(f), 10240), digest);
final byte[] temp = new byte[10240];
byte[] header = SerializableUtil.object2Byte(param);
int headerMetaLen = 4 + header.length + 8;// 4(int) + N(byte[]) + 8(long)
ByteBuffer byteBuffer = ByteBuffer.allocate(headerMetaLen);
byteBuffer.putInt(header.length);// 4
byteBuffer.put(header);// N
byteBuffer.putLong(f.length());// 8
byteBuffer.flip();
channel.writeAndFlush(new ByteBean(0, headerMetaLen, byteBuffer.array())).addListener(new ChunkedFileListener(channel, in, temp, digest));
}
public void close() {
this.connector.destroy();
}
public static void main(String[] args) throws Exception {
FileClient client = new FileClient();
final Channel channel = client.getChannel();
client.sendFile("/home/leo/Downloads/bootstrap-3.3.2-dist.zip", new Param("1","bootstrap-3.3.2-dist.zip"), channel);
//client.sendFile("/home/leo/Downloads/apache-tomcat-8.0.14.tar.gz", new Param("2","apache-tomcat-8.0.14.tar.gz"), channel);
//client.sendFile("/home/leo/Downloads/mybatis-spring-1.0.1-reference.pdf", new Param("3","mybatis-spring-1.0.1-reference.pdf"), channel);
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
client.close();
}
public class ChunkedFileListener implements GenericFutureListener<ChannelFuture> {
private final Channel channel;
private final InputStream in;
private final byte[] temp;
private final MessageDigest digest;
public ChunkedFileListener(Channel channel, InputStream in, byte[] temp, MessageDigest digest) {
this.channel = channel;
this.in = in;
this.temp = temp;
this.digest = digest;
}
@Override
public void operationComplete(ChannelFuture future) throws Exception {
int readed = in.read(temp);
if (readed == -1) {
String sha = HexUtil.bytesToHexString(digest.digest());
channel.writeAndFlush(new ByteBean(0, sha.length(), sha.getBytes()));
System.out.println("Client SHA: " + sha);
in.close();
} else {
ByteBean by = new ByteBean();
by.setContent(temp);
by.setLength(readed);
by.setPosition(0);
channel.writeAndFlush(by).addListener(new ChunkedFileListener(channel, in, temp, digest));
}
}
}
public class FileClientHandlerFactory extends ChannelHandlerFactoryAdapter {
@Override
public ChannelOutboundHandler newEncoder() {
return new MessageToByteEncoder<ByteBean>() {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBean msg,
ByteBuf out) throws Exception {
out.writeBytes(msg.getContent(), msg.getPosition(), msg.getLength());
}
};
}
@Override
public ChannelInboundHandler newInstance() {
return new ChannelInboundHandlerAdapter() {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Do nothing
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
}
};
}
}
}