简体   繁体   English

Netty:TCP 文件传输无法正常工作

[英]Netty: TCP file transfer doesn't work correctly

I am working on my online file storage and today I have encountered some issues with my Netty TCP file tranfer.我正在处理我的在线文件存储,今天我的 Netty TCP 文件传输遇到了一些问题。 So the problem is that only 8192 bytes of data is actually written in the file on the client-side.所以问题是在客户端的文件中实际上只写入了 8192 字节的数据。 I want to know what the problem is, and how I can fix it.我想知道问题是什么,以及如何解决它。

I have seen ALL of the other (5) stackoverflow questions.我已经看过所有其他 (5) 个 stackoverflow 问题。

Here is my server bootstrap:这是我的服务器引导程序:

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;
    }

}

My server-handler:我的服务器处理程序:

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
        }
    }

My client bootstrap:我的客户引导程序:

    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;
    }

}

My client handler:我的客户处理程序:

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;
    }
}

EDIT编辑

The problem was that I removed the handler too quickly, then other packets got handled in other handlers/were dropped from the pipeline.问题是我太快地删除了处理程序,然后其他数据包在其他处理程序中处理/从管道中删除。

The problem is indeed most likely to be in your FileChunkHandler.问题确实很可能出在您的 FileChunkHandler 中。

You only read a single buffer (likely containing 8192 bytes - 8kB), and then remove the handler.您只读取一个缓冲区(可能包含 8192 字节 - 8kB),然后删除处理程序。 The remaining chunks either get "handled" by some other handler in the pipeline, or reach the end of the pipeline and get dropped.剩余的块要么被管道中的其他处理程序“处理”,要么到达管道的末端并被丢弃。 As mentioned in Discord, you need to keep track of how many bytes you are expecting, subtract the number received, and only when that number reaches 0, should you remove the handler.如 Discord 中所述,您需要跟踪您期望的字节数,减去收到的数字,并且只有当该数字达到 0 时,您才应该删除处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM