[英]Netty: TCP file transfer doesn't work correctly
我正在處理我的在線文件存儲,今天我的 Netty TCP 文件傳輸遇到了一些問題。 所以問題是在客戶端的文件中實際上只寫入了 8192 字節的數據。 我想知道問題是什么,以及如何解決它。
我已經看過所有其他 (5) 個 stackoverflow 問題。
這是我的服務器引導程序:
package com.martin.main;
import com.martin.file.*;
import com.martin.handler.*;
import com.martin.utils.*;
import io.netty.bootstrap.*;
import io.netty.channel.*;
import io.netty.channel.nio.*;
import io.netty.channel.socket.*;
import io.netty.channel.socket.nio.*;
import io.netty.handler.codec.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
public class Server {
public static void main(String[] args) {
new Server().setup(4783);
}
public ChannelFuture setup(int port) {
ChannelFuture future = null;
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
final ServerBootstrap bootstrap;
// OnlineFile.getOnlineFiles().add(new OnlineFile(737389, new File("C:\\Users\\marti\\Desktop\\filesharing\\testek.txt"), "ok.txt", (int) System.currentTimeMillis(), false, "C:\\Users\\marti\\Desktop\\filesharing\\testek.txt", false, null));
try {
bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//pipeline.addLast("framer", new LengthFieldBasedFrameDecoder());
pipeline.addLast("framer", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast("login", new LoginServerHandler()); //the problem is not in that handler
}
});
future = bootstrap.bind(new InetSocketAddress(port)).sync().channel().closeFuture().sync();
}catch(InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
return future;
}
}
我的服務器處理程序:
public class ServerHandler extends ByteToMessageDecoder {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
byte msgType = byteBuf.readByte();
if(FILEPACKETINFO == msgType) {
//The problem is probaly here
System.out.println("inide file req.");
int id = byteBuf.readInt();
for(OnlineFile onlineFile : OnlineFile.getOnlineFiles()) {
if(onlineFile.getId() == id) {
System.out.println("file request id: " + id + " actual id: " + onlineFile.getId());
ByteBuf buf = Unpooled.buffer();
buf.writeByte(FILEPACKETINFO);
String fileName = onlineFile.getName();
File file = onlineFile.getActualFile();
buf.writeLong(file.length());
buf.writeInt(fileName.length());
buf.writeCharSequence(fileName, CharsetUtil.US_ASCII);
ctx.writeAndFlush(buf);
if(!(file.length() <= 0)) {
ctx.writeAndFlush(new ChunkedFile(file)).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
System.out.println("written successfully!");
if (channelFuture.cause() != null) channelFuture.cause().printStackTrace();
}
});
} else {
System.out.println("length 0: " + " (" + file.length() +")");
}
}
}
} else if(REQUESTVISUALFILES == msgType) {
createAndSend(ctx); //send VISUAL files, problem not there
} else if(REQUESTFOLDERFILESBYID == msgType) {
int id = byteBuf.readInt();
createAndSend(ctx, id); //send VISUAL files by id, problem not there
}
}
我的客戶引導程序:
public static ChannelFuture setup(String host, int port) {
ChannelFuture channelFuture = null;
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("framer", new LengthFieldBasedFrameDecoder(64*1024, 0, 4, 0, 4));
pipeline.addLast(lfp);
pipeline.addLast("login", new LoginHandler()); //the problem is not in that handler either
}
});
channelFuture = bootstrap.connect(new InetSocketAddress(host, port)).sync();
System.out.println("the setup came to an end!");
LoginForm.createAndShowGUI("Login");
mainChannel = channelFuture.channel();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
return channelFuture;
}
}
我的客戶處理程序:
package com.martin.handler;
import io.netty.buffer.*;
import io.netty.channel.*;
import io.netty.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class FileChunkHandler extends SimpleChannelInboundHandler<ByteBuf> {
public static String currentFileName = "Test.txt";
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.pipeline().remove(this);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
//the problem is probably here
System.out.println("inside FileChunkHandler current file: " + currentFileName);
ByteBuffer buffer = byteBuf.nioBuffer();
System.out.println(buffer.capacity() + " buffer" + " bytebuf: " + byteBuf.readableBytes());
File file = triggerFileCreation();
// FileOutputStream fos = new FileOutputStream("C:\\Users\\marti\\storage\\" + currentFileName);
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
FileChannel channel = randomAccessFile.getChannel();
while(buffer.hasRemaining()) {
channel.position(file.length());
channel.write(buffer);
System.out.println("chunk has just been written");
}
channel.close();
randomAccessFile.close();
//!!!--->IMPORTANT<-----!!!
ctx.pipeline().remove(this);
}
public static File triggerFileCreation() {
File file = new File(System.getProperty("user.home") + "/storage/" + currentFileName);
if(!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
}
編輯
問題是我太快地刪除了處理程序,然后其他數據包在其他處理程序中處理/從管道中刪除。
問題確實很可能出在您的 FileChunkHandler 中。
您只讀取一個緩沖區(可能包含 8192 字節 - 8kB),然后刪除處理程序。 剩余的塊要么被管道中的其他處理程序“處理”,要么到達管道的末端並被丟棄。 如 Discord 中所述,您需要跟蹤您期望的字節數,減去收到的數字,並且只有當該數字達到 0 時,您才應該刪除處理程序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.