xpg94
xpg94

Reputation: 513

Java socket receives byte array where each byte is 0

I am making a program which takes a file, and sends it via socket to client. Client receives it and saves it to a file. That is what it is supposed to do.

But somehow, byte array which client receives, contains only 0 bytes, so my output file is empty. here is the code:

Server:

try {
        serverSocket=new ServerSocket(7575);
        serverSocket.setSoTimeout(1000000);
        System.out.println("serverSocket created.");
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("Error in creating new serverSocket on port 7575");
    } 

    for(int i=0;i<array.length;i++)
        System.out.println(array[i]);

    Socket socket=null;
    try {
        System.out.println("Waiting for client...");
        socket=serverSocket.accept();
        System.out.println("Client accepted.");
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
    PrintWriter outWriter=null;
    DataOutputStream outputStream=null;
    OutputStream os=null;
    BufferedOutputStream bos=null;
    try {
        os=socket.getOutputStream();
        outputStream=new DataOutputStream(os);
        outWriter=new PrintWriter(socket.getOutputStream());
        bos=new BufferedOutputStream(socket.getOutputStream());
        System.out.println("Server streams created.");
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("sending name "+name);
    outWriter.println(name);
    outWriter.flush();

    outWriter.println(array.length);
    outWriter.println("array.length"+array.length);
    outWriter.flush();

    try {
        os.write(array);
        os.flush();
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("couldnt send array of bytes");
    }



    try {
        os.close();
       outputStream.close();

        socket.close();
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }

client:

public class Client implements Runnable {
private Socket socket;
private String folderPath;

public Client(String p)
{
    folderPath=p;
}

@Override
public void run() 
{
    try {
        System.out.println("Client connecting to localhost on 7575 port...");
        socket=new Socket("localhost", 7575);
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }

    BufferedReader reader=null;
    BufferedInputStream bis=null;
    InputStream input=null;
    DataInputStream in=null;
    try {
        System.out.println("creating streams");
        reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        input=socket.getInputStream();
        in=new DataInputStream(input);
        bis=new BufferedInputStream(socket.getInputStream());
        System.out.println("streams created!");
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    String name="";
    int size=0;
    String s="32";
    try {
        name=reader.readLine();
        s=reader.readLine();
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    if(s!=null)
    size=Integer.parseInt(s);
    System.out.println("name: "+name);
    System.out.println("size: "+size);

    byte [] arr=new byte[size];
    try {
        input.read(arr);
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("couldnt read the byte array");
    }

    for(int i=0;i<arr.length;i++)
        System.out.println(arr[i]);

    FileOutputStream fos=null;
    try {
         fos=new FileOutputStream(folderPath+"/"+name);
        } catch (FileNotFoundException ex) {
            System.out.println("Could write the file");
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    try {

        fos.write(arr);
        fos.flush();
        } catch (IOException ex) {
            System.out.println("Could write the file2");
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }

    try {
        fos.close();
        } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }


        try {
        in.close();
        input.close();
        reader.close();
        socket.close();
        } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }



}

}

Upvotes: 0

Views: 1330

Answers (3)

MadConan
MadConan

Reputation: 3767

I am making a program which takes a file, and sends it via socket to client. Client receives it and saves it to a file. That is what it is supposed to do.

If you have no need to inspect the content of what is being passed through, then straight InputStream and OutputStream are the way to go, in my opinion. The code is straightforward and fast as it avoids any overhead imposed by higher-level stream types that inspect the content for encoding, etc. This also reduces the opportunity for corrupting the information.

I agree with Stephen C's answer except for

Reading the file content into byte arrays at both ends wastes memory, and is going to be problematic for a really large file.

With the specific requirement to simply move one file to another system with no need to look at the values, this isn't an issue if you know how to handle the content. The basic flow is

client:  InputStream in = getFileInputStream();
         OutputStream out = socket.getOutputStream();
         byte[] bytes = new byte[BUFFER_SIZE]; // could be anything
         int bytesRead;
         while((bytesRead = in.read(bytes)) != -1){
             out.write(bytes,0,bytesRead);
         }
         in.close();
         out.close();

server:  InputStream in = socket.getInputStream();
         OutputStream out = getFileOutputStream();
         // the rest is the exact same thing as the client

This will handle any arbitrarily sized file, limited only by disk size of the server.

Here is an example I whipped up. It's admittedly hacky (the use of the FILE_COUNTER and STOP_KEY for example) but I'm only attempting to show various aspects of having a user enter a file and then send it between a client and server.

public class FileSenderDemo {

    private static final int PORT = 7999;
    private static final String STOP_KEY = "server.stop";

    private static final int[] FILE_COUNTER = {0};

    public static void main(String[] args) {

        FileSenderDemo sender = new FileSenderDemo();

        Thread client = new Thread(sender.getClient());
        Thread server = new Thread(sender.getServer());

        server.start();
        client.start();
        try {
            server.join();
            client.join();
        } catch (InterruptedException e) {
            FILE_COUNTER[0] = 999 ;
            System.setProperty(STOP_KEY,"stop");
            throw new IllegalStateException(e);
        }
    }

    public void send(File f, OutputStream out) throws IOException{
        try(BufferedInputStream in = new BufferedInputStream(new FileInputStream(f),1<<11)){
            byte[] bytes = new byte[1<<11];
            int bytesRead;
            while((bytesRead = in.read(bytes)) != -1){
                out.write(bytes,0,bytesRead);
            }
        }
    }

    public Runnable getClient() {
        return () -> {
            while(FILE_COUNTER[0] < 3 && System.getProperty(STOP_KEY) == null) {
                Socket socket;
                try {
                    socket = new Socket("localhost", PORT);
                } catch (IOException e) {
                    throw new IllegalStateException("CLIENT: Can't create the client: " + e.getMessage(), e);
                }

                File f = getFile();

                try (BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream())) {
                    send(f, out);
                } catch (IOException e) {
                    System.out.println("CLIENT: Failed to send file " + f.getAbsolutePath()+" due to: " + e.getMessage());
                    e.printStackTrace(System.err);
                } finally {
                    FILE_COUNTER[0]++;
                }
            }
            System.setProperty(STOP_KEY,"stop");
        };
    }

    public File getFile(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("CLIENT: Enter a file Name: ");
        return new File(scanner.next());
    }

    public Runnable getServer(){
        return () -> {
            OutputStream out = null;
            try{
                ServerSocket server = new ServerSocket(PORT);
                server.setSoTimeout(20000);
                while(System.getProperty(STOP_KEY) == null){
                    Socket socket = null;
                    try {
                        socket = server.accept();
                    }catch (SocketTimeoutException e){
                        System.out.println("SERVER: Waited 20 seconds for an accept.  Now checking if we need to stop.");
                        continue;
                    }
                    String fileName = "receivedFile_"+System.currentTimeMillis()+".content";
                    File outFile = new File(fileName);
                    out = new BufferedOutputStream(new FileOutputStream(outFile));
                    InputStream in = socket.getInputStream();
                    int bytesRead;
                    byte[] bytes = new byte[1<<12];
                    while((bytesRead = in.read(bytes)) != -1){
                        out.write(bytes,0,bytesRead);
                    }
                    out.close();
                    socket.close();
                    System.out.println("SERVER: Just created a new file: " + outFile.getAbsolutePath());
                }
                System.out.println("SERVER: " + STOP_KEY + " was not null, so quit.");
            }catch (IOException e){
                throw new IllegalStateException("SERVER: failed to receive the file content",e);
            }finally {
                if(out != null){
                    try{out.close();}catch (IOException e){}
                }
            }
        };
    }
}

Upvotes: 1

Stephen C
Stephen C

Reputation: 719551

Mixing binary and text modes on the same stream is tricky. You would be advised not to do it. Using DataInputStream (for the name, count and file content) is one possible solution. (And that is what I would try). Another would be to encode the file content as text (e.g. using Base64 encoding).

The problem with your current "mixed stream: code is on the client side. When you read the name and size from the BufferedReader, you will cause the reader to read and buffer up to 4096 bytes from the socket. The problem is that some of those bytes are file content. So when you then try to read the content from the underlying InputStream here:

    input.read(arr);

you may find that there is nothing left to read. Result: an empty or corrupted file.


There's another problem too. Your code assumes that the input.read(arr) statement is going to read the rest of the stream, or until it fills the byte array. This assumption is incorrect. When you are reading from a socket stream, the read is liable to return only the bytes that are currently available (in the client-side network stack).

Once again, the result is liable to be a corrupted file. (In this case truncated.)

The read code should look something like this:

  int count = 0;
  while (count < size) {
      int bytesRead = is.read(bytes, count, bytes.length - count);
      if (bytesRead == -1) {
           throw EOFException("didn't get a complete file");
      }
      count += bytesRead;
  }

Finally:

  • Reading the file content into byte arrays at both ends wastes memory, and is going to be problematic for a really large file.

  • You really should be using "try with resources" to ensure that the streams are all closed properly. Doing it by hand is cumbersome, and risks resource leaks.

Upvotes: 3

Sushant Srivastava
Sushant Srivastava

Reputation: 307

you can use DataOutputStream to directly write some string(message) on output stream using writeUTF() function. And then u can receive your message using object of DataInputStream class by using readUTF() method.

u can send data using following:-

String message="something";
DataOutputStream out=new DataOutputStream(socket.getOutputStream());
out.writeUTF(message);

and u can receive data or message using following:-

 DataInputStream in=new DataInputStream(socket.getInputStream());
 String message=in.readUTF();

i basically used these method to read data from input stream and write data to outputstream many times and it worked every time, so u should check this way too.

Upvotes: 1

Related Questions