How to send images through sockets in java?
Asked Answered
T

2

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!

Tempestuous answered 1/8, 2014 at 18:55 Comment(7)
Try flush after ImageIO.write.Airtight
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?Tempestuous
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.Oar
How exactly? I'm pretty new in java, can i ask you to write the code? Thanks!Tempestuous
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.Oar
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...Tempestuous
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.Jacklight
A
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();
    }

}
Airtight answered 2/8, 2014 at 14:57 Comment(5)
It still disconnects me, i don't know why :/Tempestuous
Run Receive.main (it will wait) and then run Send.main. Does this work?Airtight
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.Tempestuous
ImageIO.read() closes the input unless it is an ImageInputStream. See the Javadoc.Jacklight
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/imageBluebonnet
L
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();
        }
    }
}
Loppy answered 11/3, 2015 at 17:42 Comment(2)
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....Romans
docs.oracle.com/javase/7/docs/api/java/net/…Loppy

© 2022 - 2024 — McMap. All rights reserved.