0

I am puzzle with my latest predicament with Java Socket programming for three days straight now. I use NIO ByteBuffer and Channel to transfer byte from client to server. I test my code by having client to send 2 files in sequences - the first files always arrived but the second one is always lost so where. I did tcpdump and I saw the traffic in specific address and port but I could not decipher pcap's file (understand how to read all the syntax in the pcap files).

somehow socketchannel.read(bytebuffer) is not reading any byte for the 2nd file. the first file will be okay. It passes through the read command, receives file, and respond. the second file will be okay for read command and respond. it does not receive any file for socketchannel.read is getting -1 --- THAT is the problem.

Please do help. This is really crazy problem.

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

That ServerThread implements runnable that is being call by other class ServerMain that pass only serversocket.accept() into ServersThread(Socket socket)

Here is ServerMain class:

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

Here is the client class

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

}
EdisonCh
  • 13
  • 1
  • 7
  • I had verified using tcpdump and wireshark that client sent the data and server received the byte as plan. I studied the ACK, PSH ACK, SYN, FIN ACK - of wireshark and pcap file. However in the java's level the sc.read(dst) != 1 is still happening! very puzzling! anyone up for suggestion? I am at the wit end now. – EdisonCh May 24 '14 at 06:05

2 Answers2

0

When reading the first upload, you're reading until end of stream, including all the second file. So when you go to read the second file there is nothing left. You need to send yourself the file length, ahead of the file, and only read that many bytes.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • If you see Client's main's method, I send one file and it ends (close all socket). I send another file by starting the process over again in client and in server side. The second run Servers still can read and reply the command and the respond; however, it is always come out with empty sc.read(dst) therefore no file is written. – EdisonCh May 24 '14 at 03:04
  • You're still reading the socket channel until end of file. That only happens when the peer closes the connection. – user207421 May 25 '14 at 08:02
0

After spending about 12 days straight with these problem, I finally have somehow solve the problem even though I can't explain why the problem happens in the first place. The problem is tricky because it happens almost all the time. Inconsistent file delivery.

I change the protocol of the application.

Original protocol for client 1. Send String order 2. Send actual file 3. Receive server's acknowledgement

New protocol for client 1. Send String order 2. Receive server's acknowledgement 3. Send actual file 4. Receive server's acknowledgement

Due to new protocol, the sending file becomes consistent.

Thanks anyway.

EdisonCh
  • 13
  • 1
  • 7