9

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!

enemy
  • 101
  • 1
  • 1
  • 3
  • 3
    Try flush after ImageIO.write. – jakub.petr Aug 01 '14 at 19:03
  • I already tried it, but it doesn't work. The only way i have to make it work is: socket.close(); or out.close(); Any other has any idea? I saw on the internet people suggesting to send the image as bytes, but i don't have any idea how to do it.. Any other suggestion? – enemy Aug 01 '14 at 23:54
  • I would say you are using the wrong method for client/server use RMI to connect a client to a server to pass data back and forth. – JRSofty Aug 02 '14 at 00:05
  • How exactly? I'm pretty new in java, can i ask you to write the code? Thanks! – enemy Aug 02 '14 at 00:12
  • I've been informed that my attempt to answer your question wasn't good enough, so I've deleted it. Maybe the person who knows better can take the time to help you. – JRSofty Aug 02 '14 at 11:32
  • I didnt even have the time to test it, maybe it was good for me.. Anyway, is it possble that there is no function for send images? For objects it exists... – enemy Aug 02 '14 at 12:48
  • `while(!socket.isClosed())` is not a valid test. It won't be true until you close it. You should test the result of `readLine()` for null. But you shouldn't be mixing readers and writers and streams and buffered and unbuffered on the same socket anyway: it will never work. – user207421 Dec 05 '16 at 01:11

2 Answers2

17

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

}
jakub.petr
  • 2,951
  • 2
  • 23
  • 34
  • 1
    It still disconnects me, i don't know why :/ – enemy Aug 02 '14 at 16:05
  • Run Receive.main (it will wait) and then run Send.main. Does this work? – jakub.petr Aug 02 '14 at 17:11
  • 1
    It works even in my code (if i copy it), but it disconnects after it. Also, the images i receive are only a part of the real screenshot. – enemy Aug 02 '14 at 17:32
  • 1
    ImageIO.read() closes the input unless it is an ImageInputStream. See the Javadoc. – user207421 Aug 02 '14 at 17:49
  • Why i can't display the image in the browser? How can i send an image through socket and display it by an http, such as : `http://localhost:13085/image` – Sajad Aug 30 '15 at 22:02
6

You can find a (non-compiling) example at easywayprogramming.

I have simplified it and fixed the errors, I hope that this is a useful answer to your question.

Run the server first, then run the client as often as you want.

The example will take a screenshot of the upper left 200x100 pixels of your screen, send them to the server which will open a new window and display the screenshot.

GreetingServer.java

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.sql.SQLException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class GreetingServer extends Thread
{
       private ServerSocket serverSocket;
       Socket server;

       public GreetingServer(int port) throws IOException, SQLException, ClassNotFoundException, Exception
       {
          serverSocket = new ServerSocket(port);
          serverSocket.setSoTimeout(180000);
       }

       public void run()
       {
           while(true)
          { 
               try
               {
                  server = serverSocket.accept();
                  BufferedImage img=ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));
                  JFrame frame = new JFrame();
                  frame.getContentPane().add(new JLabel(new ImageIcon(img)));
                  frame.pack();
                  frame.setVisible(true);                  
              }
             catch(SocketTimeoutException st)
             {
                   System.out.println("Socket timed out!");
                  break;
             }
             catch(IOException e)
             {
                  e.printStackTrace();
                  break;
             }
             catch(Exception ex)
            {
                  System.out.println(ex);
            }
          }
       }

       public static void main(String [] args) throws IOException, SQLException, ClassNotFoundException, Exception
       {
              Thread t = new GreetingServer(6066);
              t.start();
       }
}

GreetingClient.java

import java.awt.AWTException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.Socket;

import javax.imageio.ImageIO;

public class GreetingClient
{
    Image newimg;
    static BufferedImage bimg;
    byte[] bytes;

    public static void main(String [] args)
    {
        String serverName = "localhost";
        int port = 6066;
        try
        {
            Socket client = new Socket(serverName, port);
            Robot bot;
            bot = new Robot();
            bimg = bot.createScreenCapture(new Rectangle(0, 0, 200, 100));
            ImageIO.write(bimg,"JPG",client.getOutputStream());
            client.close();
        } catch(IOException | AWTException e) {
            e.printStackTrace();
        }
    }
}
user2707001
  • 1,543
  • 12
  • 13
  • 1
    this code is fine if only the image is small... but once i use a bigger size for the image, some error occured by less than 2 minutes when the program runs.... – gumuruh Dec 19 '17 at 10:34
  • 1
    https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#setSoTimeout%28int%29 – user2707001 Dec 19 '17 at 21:22