私はネッティーに新たなんです。日のために私を混乱ファイル転送に関する問題があります。私は、送信したい画像クライアントからサーバにファイルを。
以下のコードは、実行可能です。しかし、唯一のI シャットダウンサーバーは強制的に私は正常に受信した画像ファイルを開くことができます。それ以外の場合は、「表示さあなたはこのファイルを表示する権限を持っていないように見えます。権限を確認して再試行してください」。使用ByteBufにデータがないとき、近くのFileOutputStreamにしたい私はそう)ByteBuf.isReadableは(が、ServerHandlerにおける方法channelReadで他のブロックが届くことはありません。無駄だ。
送信場合のほか、テキストファイルをサーバーがあるとき、それは正常に開くことができる生きています。私は、シャットダウン・サーバーに転送後に毎回必要はありません。私はそれを解決するためにいくつかの提案をお願いします。
これはFileClientHandlerです
public class FileClientHandler extends ChannelInboundHandlerAdapter {
private int readLength = 8;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
sendFile(ctx.channel());
}
private void sendFile(Channel channel) throws IOException {
File file = new File("C:\\Users\\xxx\\Desktop\\1.png");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
for (;;) {
byte[] bytes = new byte[readLength];
int readNum = bis.read(bytes, 0, readLength);
// System.out.println(readNum);
if (readNum == -1) {
bis.close();
fis.close();
return;
}
sendToServer(bytes, channel, readNum);
}
}
private void sendToServer(byte[] bytes, Channel channel, int length)
throws IOException {
channel.writeAndFlush(Unpooled.copiedBuffer(bytes, 0, length));
}
}
これはFileServerHandlerです
public class FileServerHandler extends ChannelInboundHandlerAdapter {
private File file = new File("C:\\Users\\xxx\\Desktop\\2.png");
private FileOutputStream fos;
public FileServerHandler() {
try {
if (!file.exists()) {
file.createNewFile();
} else {
file.delete();
file.createNewFile();
}
fos = new FileOutputStream(file);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
try {
ByteBuf buf = (ByteBuf) msg;
if (buf.isReadable()) {
buf.readBytes(fos, buf.readableBytes());
fos.flush();
} else {
System.out.println("I want to close fileoutputstream!");
buf.release();
fos.flush();
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
サーバー側の修正
ネッティーの世界では、複数の「イベント」はあります。
これらの「イベント」のうち、あなたはおそらく既に知っているchannelRead
(あなたがそれを使用しているため)していますが、必要に思えることを別のものですchannelInactive
。この1は、ときに、他のエンドポイント閉まり接続ダウンと呼ばれ、あなたはこのようにそれを使用することができます:
@Override
public void channelInactive(ctx) {
System.out.println("I want to close fileoutputstream!");
fos.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
try {
ByteBuf buf = (ByteBuf) msg;
// if (buf.isReadable()) { // a buf should always be readable here
buf.readBytes(fos, buf.readableBytes());
// fos.flush(); // flushing is always done when closing
//} else {
// System.out.println("I want to close fileoutputstream!");
// buf.release(); // Should be placed in the finally block
// fos.flush();
// fos.close();
//}
} catch (Exception e) {
e.printStackTrace();
} finally {
buf.release(); // Should always be done, even if writing to the file fails
}
}
しかし、どのようにサーバは接続がシャットダウンを持って知っていますか?現時点では、クライアントはサーバーダウンをシャットし、代わりに永遠に生きて接続を維持するバックグラウンドで実行し続けることはありません。
クライアント側の修正
正常にシャットダウンクライアントからの接続のために、我々は呼び出す必要がありchannel.close()
、これはデータを送信し、ネットワーク層で接続を閉じ、潜在的にデータをドロップするとの競合状態が発生すると、しかし、我々は直接、戻りラインの前にこれを挿入することはできません。
適切にこれらの条件を処理するために、ネッティーは使用していますFuture
非同期アクションが起こるの後のコードがイベントを処理することを可能にするシステムを。
ラッキーは私たちのために、網状が既に溶液中のビルドあり、このために、私たちはそれを配線する必要があります。私たちのコードに、このソリューションを配線するには、我々は、最新のトラック維持する必要がありChannelFuture
ネッティーの書き込み方法により放出されたが。
適切にこのソリューションを実装するために、我々は変更sendToServer
writeメソッドの結果を返すために:
private ChannelFuture sendToServer(byte[] bytes, Channel channel, int length)
throws IOException {
return channel.writeAndFlush(Unpooled.copiedBuffer(bytes, 0, length));
}
その後、我々は、我々は接続を閉じたいときに、この戻り値を追跡し、その溶液中に網状のビルドを含むリスナーを追加しておきます:
ChannelFuture lastFuture = null;
for (;;) {
byte[] bytes = new byte[readLength];
int readNum = bis.read(bytes, 0, readLength);
// System.out.println(readNum);
if (readNum == -1) {
bis.close();
fis.close();
if(lastFuture == null) { // When our file is 0 bytes long, this is true
channel.close();
} else {
lastFuture.addListener(ChannelFutureListener.CLOSE);
}
return;
}
lastFuture = sendToServer(bytes, channel, readNum);
}