0

I want to create a simple multiple file transfer program using java socket.

server output:

I am server
The server is listening...
Client are connected
Files Selected : 2
README.txt
vcruntime140.dll
Server Closed!

client output:

i am client
Server are connected
filecount : 2
filenames : README.txt

Exception in thread "main" java.io.EOFException at java.io.DataInputStream.readFully(Unknown Source) at java.io.DataInputStream.readLong(Unknown Source) at socket.client.main(client.java:32)

This is my server code! server is sender.

public static void main(String[] args) throws Exception {

    System.out.println("i am server");
    System.out.println("");
    server = new ServerSocket(12345);
    System.out.println("Server is listening...");
    client = server.accept();
    System.out.println("Client are connected");
    dos = new DataOutputStream(client.getOutputStream());


    dir = "C:\\Users\\Nitesh Rathi\\Downloads\\vcruntime140";
    files = new File(dir).listFiles();
    System.out.println("Files Selected : " + files.length);

    dos.writeInt(files.length);

    byte[] b = new byte[4096];

    for (File file : files)
    {
        long length = file.length();
        dos.writeLong(length);

        String filename = file.getName();
        dos.writeUTF(filename);

        System.out.println(file.getName());
        fis = new FileInputStream(file);

        while (fis.read(b) != -1)
        {
            fis.read(b, 0, b.length);
            dos.write(b, 0, b.length);
        }
    }

    System.out.println("");
    fis.close();
    client.close();
    server.close();
    System.out.println("Server Closed!");
}

This is my client code! client is receiver.

public static void main(String[] args) throws Exception {

    System.out.println("i am client");
    System.out.println("");
    soc = new Socket("localhost", 12345);
    System.out.println("Server are connected");
    dis = new DataInputStream(soc.getInputStream());

    int filecount = dis.readInt();
    File[] files = new File[filecount];

    System.out.println("filecount : " + filecount);
    byte[] b = new byte[1024];

    for (int i=0;i<filecount;i++)
    {
        long filelength = dis.readLong();
        String filename = dis.readUTF();
        System.out.println("filenames : "+filename);

        files[i] = new File(dirPath + "/" + filename);
        fos = new FileOutputStream(files[i]);

        for(int j = 0; j < filelength; j++)
        {
            fos.write(b);
            dis.read(b);
        }

    }

    System.out.println("data received!");

    fos.flush();
    fos.close();
    soc.close();

    System.out.println("client closed!");
}

I expect this output of the client: File count : 2 File names : README.txt vcruntime140.dll

matesio
  • 1,584
  • 17
  • 31
  • Your read loops don't quite make any sense. You **must** save the number bytes read; this number is returned by `read()`. This is the number you supply to the subsequent write. And you are just throwing away data in your server read loop because you read once in the while loop conditional and then again in the while loop body. Maybe you can use some of the Stream classes in the Google Guava library to simply this for you. – President James K. Polk Jul 08 '19 at 20:52
  • Too many basic errors here. Throw it all away and use my answer in the duplicate. – user207421 Jul 09 '19 at 01:41

2 Answers2

1

On the server side, you are calling fis.read() twice per loop iteration while reading from an input file stream. You need to call it only once per iteration, and you need to pass the return value of fis.read() to dos.write() so it knows the correct number of bytes to write.

On the client side, while reading a file stream, you are calling fos.write() before you have called dis.read() to populate b with data. And you are looping too many times, as you are not updating your j loop counter with the number of bytes actually read per iteration.

Try something more like this instead:

Server:

public static void main(String[] args) throws Exception
{
    System.out.println("i am server");
    System.out.println("");

    ServerSocket server = new ServerSocket(12345);
    System.out.println("Server is listening...");

    Socket client = server.accept();
    System.out.println("Client is connected");

    DataOutputStream dos = new DataOutputStream(client.getOutputStream());

    String dir = "C:\\Users\\Nitesh Rathi\\Downloads\\vcruntime140";
    Files[] files = new File(dir).listFiles();

    System.out.println("Files Selected : " + files.length);
    dos.writeInt(files.length);

    byte[] b = new byte[4096];

    for (File file : files)
    {
        long filelength = file.length();
        dos.writeLong(filelength);

        String filename = file.getName();
        dos.writeUTF(filename);
        System.out.println(filename);

        FileInputStream fis = new FileInputStream(file);
        DataInputStream dis = DataInputStream(fis);

        int loops = (int) (filelength / (long) b.length);
        int remainder = (int) (filelength % (long) b.length);

        for (int j = 0; j < loops; j++) 
        {
            dis.readFully(b);
            dos.write(b);
        }

        if (remainder > 0)
        {
            dis.readFully(b, 0, remainder);
            dos.write(b, 0, remainder);
        }
    }

    System.out.println("");

    dos.close();
    server.close();

    System.out.println("Server Closed!");
}

Client:

public static void main(String[] args) throws Exception
{
    System.out.println("i am client");
    System.out.println("");

    Socket soc = new Socket("localhost", 12345);
    System.out.println("Server is connected");

    DataInputStream dis = new DataInputStream(soc.getInputStream());

    int filecount = dis.readInt();
    File[] files = new File[filecount];
    System.out.println("filecount : " + filecount);

    byte[] b = new byte[1024];

    for (int i = 0; i < filecount; i++)
    {
        long filelength = dis.readLong();
        String filename = dis.readUTF();
        System.out.println("filename : " + filename);

        files[i] = new File(dirPath + "/" + filename);

        FileOutputStream fos = new FileOutputStream(files[i]);

        int loops = (int) (filelength / (long) b.length);
        int remainder = (int) (filelength % (long) b.length);

        for (int j = 0; j < loops; j++)
        {
            dis.readFully(b);
            fos.write(b);
        }

        if (remainder > 0)
        {
            dis.readFully(b, 0, remainder);
            fos.write(b, 0, remainder);
        }
    }

    System.out.println("data received!");

    dis.close();

    System.out.println("client closed!");
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Just to have an example of how code can get cleaner using the Google Gauva library, here is your code changed to use a couple of utility classes from Guava, ByteStreams and Files

import com.google.common.io.ByteStreams;
import com.google.common.io.Files;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientServerGuava {
    private static final int PORT = 12345;

    public static void main(String[] args) throws IOException {
        Thread serverThread = new ServerThread();
        serverThread.start();
        runClient();
    }

    private static void runClient() throws IOException {
        System.out.println("i am client");
        System.out.println("");
        Socket soc = new Socket("localhost", PORT);
        System.out.println("Server are connected");
        DataInputStream dis = new DataInputStream(soc.getInputStream());

        int filecount = dis.readInt();
        File[] files = new File[filecount];

        System.out.println("filecount : " + filecount);
        byte[] b = new byte[1024];

        for (int i=0;i<filecount;i++)
        {
            long filelength = dis.readLong();
            String filename = dis.readUTF();
            System.out.println("filenames : "+filename);

            files[i] = new File(filename);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(files[i]));
            InputStream limitedStream = ByteStreams.limit(dis, filelength);
            ByteStreams.copy(limitedStream, bos);
            bos.close();

        }

        System.out.println("data received!");
        dis.close();
        soc.close();

        System.out.println("client closed!");
    }

    private static class ServerThread extends Thread {

        private static final String DIR = "C:\\Users\\Nitesh Rathi\\Downloads\\vcruntime140";

        @Override
        public void run() {
            try {
                System.out.println("i am server");
                System.out.println("");
                ServerSocket server = new ServerSocket(PORT);
                System.out.println("Server is listening...");
                Socket client = server.accept();
                System.out.println("Client are connected");
                DataOutputStream dos = new DataOutputStream(client.getOutputStream());


                String dir = DIR;
                File[] files = new File(dir).listFiles();
                System.out.println("Files Selected : " + files.length);

                dos.writeInt(files.length);

                for (File file : files) {
                    dos.writeLong(file.length());
                    dos.writeUTF(file.getName());

                    System.out.println(file.getName());

                    Files.copy(file, dos);
                }

                System.out.println("");
                dos.close();
                client.close();
                server.close();
                System.out.println("Server Closed!");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

Notice the elimination of the read loops. You really should learn how to code a read loop, but in practice you will likely be better served relying on a supported, analyzed, mature, optimized library. I believe Apache commons-io has similar functionality.

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125