Java Socket.read(ByteBuffer dst) не получает ни одного байта

Я ломаю голову над своим последним затруднением с программированием на Java Socket уже три дня. Я использую NIO ByteBuffer и Channel для передачи байта от клиента к серверу. Я проверяю свой код, заставляя клиента отправлять 2 файла в последовательности - первые файлы всегда поступают, а второй всегда теряется, где. Я сделал tcpdump и увидел трафик по конкретному адресу и порту, но я не смог расшифровать файл pcap (понять, как прочитать весь синтаксис в файлах pcap).

каким-то образом socketchannel.read (bytebuffer) не читает ни одного байта для второго файла. первый файл будет в порядке. Он проходит через команду чтения, получает файл и отвечает. второй файл будет в порядке для команды чтения и ответа. он не получает никакого файла для socketchannel.read получает -1 --- В этом проблема.

Пожалуйста, помогите. Это действительно сумасшедшая проблема.

public class ServersThread implements Runnable 
{
    private Socket socket;

    public ServersThread(Socket socket)
    {
        this();
        this.socket = socket;
    }

    public void run()
    {
        try
        {
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        BufferedReader br = new BufferedReader(isr);
        PrintStream ps = new PrintStream(socket.getOutputStream(), true);

        String orderFromClient = br.readLine(); // first read command from client

        String filename = orderFromClient.split(":")[0]
        long fileSize = Long.parseLong(orderFromClient.split(":")[1]);

        File destFile = new File(filename);         
        destFile.setReadable(true);
        destFile.setWritable(true);

        FileOutputStream inFile = new FileOutputStream(destFile);
        FileChannel inChannel = inFile.getChannel();


        SocketChannel sc = socket.getChannel();
        ByteBuffer dst = ByteBuffer.allocate(65536);
        dst.clear();

        // this receiving binary file part that is questionable.
        // it always run okay for the first file
        // the second file is created but always has size 0
                    // The second file will enter into while-loop start and end but it won't enter sc.read(dst)

        logger.debug(AUDIT,"while-loop start");
        start = System.currentTimeMillis();
        while (sc.read(dst) != -1)
        {
            dst.flip();
            logger.debug(AUDIT,"dst flip and ask remaining: {} at position {}",dst.hasRemaining(),dst.position());
            while (dst.hasRemaining())
            {
                temp = inChannel.write(dst);
                curnset += temp;
                logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp, fileSize);
            }
            dst.clear();
        }
        end = System.currentTimeMillis();
        logger.debug(AUDIT,"while-loop end");

        if (curnset == fileSize)
            ps.println("SUCCESS");
        else
            ps.println("FAIL");

        }
        catch(Exception e)
        {
            e.printStackTrace(System.err);
            logger.error("Exception ",e);
        }
        finally
        {
            try
            {
                inChannel.close();
                inFile.close();
                sc.close();
                ps.close();
                isr.close();
                br.close();
                socket.close();
            }
            catch(IOException e)
            { }
        }
    }
}

В этом ServerThread реализован runnable, вызываемый другим классом ServerMain, который передает только serversocket.accept() в ServersThread(сокет Socket)

Вот класс ServerMain:

public class ServerMain
{

    public static void main(String[] args)
    {
        ServerSocketChannel listener = null;
        ServerSocket serverMain = null;

        try
        {
            listener = ServerSocketChannel.open();
            serverMain = listener.socket();
            serverMain.setReuseAddress(true);
            serverMain.bind(new InetSocketAddress("192.168.1.12",9999));

            while (true)
            {
                new ServersThread(serverMain.accept()).start();
            }

        }
        catch (Exception e)
        {
            logger.error("Exception ", e);
            e.printStackTrace(System.err);
        }
        finally
        {
            try
            {
                listener.close();
            }
            catch (IOException e)
            {
                logger.error("IOException ", e);
                e.printStackTrace(System.err);
            }
        }
    }
}

Вот класс клиента

public class ClientCallable
{

    public static void process(String serverAddr,int serverPort,File file,String command)
    {
        SocketChannel sc = null;
        PrintStream ps = null;
        BufferedReader br = null;
        int timeout = 10 * 1000;
        try
        {
            sc = SocketChannel.open();
            sc.configureBlocking(true);

            if (!sc.connect(new InetSocketAddress(serverAddr, serverPort)))
                return ClientMain.ERROR_UNABLE_TO_CONNECT;
            sc.socket().setSoTimeout(timeout);

        }
        catch (Exception e)
        {
            logger.error("Exception ", e);
            e.printStackTrace(System.err);
            return;
        }

        long maxCount = 8192 * 1024;
        long curnset = 0l;
        long temp = 0l;
        long filesize = 0l;
        long startTime = 0l;
        long endTime = 0l;
        String serverResp = null;
        FileInputStream fis = null;
        FileChannel fc = null;
        try
        {
            ps = new PrintStream(sc.socket().getOutputStream());
            br = new BufferedReader(new InputStreamReader(sc.socket()
                    .getInputStream()));
            fis = new FileInputStream(file);
            fc = fis.getChannel();
            filesize = fc.size();

            // send command to server
            ps.print(command);

            // send binary file
            ByteBuffer dst = ByteBuffer.allocate(65536);
            dst.clear();
            startTime = System.currentTimeMillis();
            while (fc.read(dst) != -1)
            {
                dst.flip();
                while (dst.hasRemaining())
                {
                    temp = sc.write(dst);
                    curnset += temp;
                    logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp,
                            filesize);
                }
                dst.clear();
            }
            sc.shutdownOutput();
            endTime = System.currentTimeMillis();

            // read server respond
            serverResp = br.readLine();
            logger.debug(AUDIT,"server responds {}",serverResp);
        }
        catch (Exception e)
        {
            logger.error("Exception ", e);
            e.printStackTrace(System.err);
        }

        try
        {
            if (fis != null)
                fis.close();
            if (fc != null)
                fc.close();
            if (ps != null)
                ps.close();
            if (br != null)
                br.close();
            if (sc != null)
                sc.close();
        }
        catch (Exception e)
        {
            logger.error("Exception ", e);
            e.printStackTrace(System.err);
        }

    }

    public static void main(String[] args)
    {
        String serverAddr = "192.168.1.12"
        int serverPort = 9999;
        File file1 = new File("file1.fpt");
        File file2 = new File("file2.fpt");
        String command = "somecommandtoserver";
        process(serverAddr,serverPort,file1,command);
        process(serverAddr,serverPort,file2,command);
    }

}

2 ответа

Решение

Потратив около 12 дней на решение этой проблемы, я, наконец, каким-то образом решил эту проблему, хотя не могу объяснить, почему проблема возникает в первую очередь. Проблема хитрая, потому что это происходит почти все время. Несогласованная доставка файлов.

Я изменяю протокол приложения.

Исходный протокол для клиента 1. Отправить строку заказа 2. Отправить фактический файл 3. Получить подтверждение сервера

Новый протокол для клиента 1. Отправить строку заказа 2. Получить подтверждение сервера 3. Отправить фактический файл 4. Получить подтверждение сервера

Благодаря новому протоколу отправка файла становится согласованной.

Спасибо, в любом случае.

При чтении первой загрузки вы читаете до конца потока, включая весь второй файл. Поэтому, когда вы идете читать второй файл, ничего не остается. Вам нужно отправить себе длину файла, опередив файл, и прочитать только столько байтов.

Другие вопросы по тегам