How to send images through sockets in java?

enemy picture enemy · Aug 1, 2014 · Viewed 59.4k times · Source

I am writing a client-server program and I want that to send an image. The code is the following:

//RECEIVER
while(true){
  try{
            socket = server.accept();

            out = new ObjectOutputStream(socket.getOutputStream());
            out.flush();
            in = new ObjectInputStream(socket.getInputStream());

            System.out.println("Connected to "+PORTA+".");

            while(!socket.isClosed()){ 
                System.out.println("\nPrint the action");
                azione = reader.readLine();

           if(azione.equals("screenshot")){

                    out.writeObject("screenshot");
                    out.flush();
                    BufferedImage screenshot = ImageIO.read(in);

                    ImageIO.write(screenshot, "jpg", new File("screenshot.jpg"));
                }
  }catch(Exception ex){
            System.out.println("Not connected.\n");
  } 
}

And the server:

while(true){ 
   try{
            socket = new Socket(INDIRIZZO, PORT);

            out = new ObjectOutputStream(socket.getOutputStream());
            out.flush();
            in = new ObjectInputStream(socket.getInputStream());

            while(!socket.isClosed()){
                try {
                  action = (String)in.readObject();
                  if(azione.equals("screenshot")){
                        BufferedImage screenshot = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
                        ImageIO.write(screenshot, "jpg", out);
                    }catch(Exception e){

                    }
            }
   }catch(Exception ex){
      //
   }
}

My problem is that the client receive the image only if I close the socket or the out stream, but I don't want that to happen. How can I bypass that? How can I send the image as bytes? Thanks!

Answer

jakub.petr picture jakub.petr · Aug 2, 2014

The problem is that ImageIO.read waits for the end of the stream. Sockets send it only when you close it. (which makes sense)

What you want to do is to first send size of the image and on the receiver side to read the image as byte array.

public class Send {

    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 13085);
        OutputStream outputStream = socket.getOutputStream();

        BufferedImage image = ImageIO.read(new File("C:\\Users\\Jakub\\Pictures\\test.jpg"));

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpg", byteArrayOutputStream);

        byte[] size = ByteBuffer.allocate(4).putInt(byteArrayOutputStream.size()).array();
        outputStream.write(size);
        outputStream.write(byteArrayOutputStream.toByteArray());
        outputStream.flush();
        System.out.println("Flushed: " + System.currentTimeMillis());

        Thread.sleep(120000);
        System.out.println("Closing: " + System.currentTimeMillis());
        socket.close();
    }
}


public class Receive {

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(13085);
        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();

        System.out.println("Reading: " + System.currentTimeMillis());

        byte[] sizeAr = new byte[4];
        inputStream.read(sizeAr);
        int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();

        byte[] imageAr = new byte[size];
        inputStream.read(imageAr);

        BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageAr));

        System.out.println("Received " + image.getHeight() + "x" + image.getWidth() + ": " + System.currentTimeMillis());
        ImageIO.write(image, "jpg", new File("C:\\Users\\Jakub\\Pictures\\test2.jpg"));

        serverSocket.close();
    }

}