2016-12-20 3 views
3

Im работает над пробной программой, но в какой-то степени полезен.Java отправить скриншот через сокет

Что я пытаюсь сделать, это получить скриншоты от клиента и открыть скриншот на сервере как JFrame.

После многочисленных попыток я нашел этот нерешенный вопрос How to send images through sockets in java?.

Скриншот проникает, но его нарезанный и только около 120-135kb пробивает его. В верхнем голосовавшем ответе у него есть Thread.sleep() на стороне клиента, прежде чем он закрывает соединение, но я попробовал его без него, и он вышел измельченный, поэтому я попробовал его, как он выразился, но он все еще вернулся нарезанный. Мой клиентский класс, который считывает входные данные, находится в цикле и запускается каждые 100 мс, поэтому я думал, что он слишком быстро зацикливается, поэтому я увеличил его до 1000 мс, и он все еще был нарезанным.

Я пытался что-то другое на тот же поток, с другим ответом и изменить на стороне сервера ImageIO.read(new ByteArrayInputStream(imageAr)) к ImageIO.read(new ByteArrayInputStream(imageAr)) но это время изображения не пришло.

Это был один из первых методов, которые я пробовал, когда я начал но это не сработало! https://javabelazy.blogspot.com/2013/10/sending-screenshot-from-client-to.html.

Сервер

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

Эта часть кода сервера является новым потоком, создавая новый сокет и новый JFrame для отображения экрана. Почему я это делаю? В другом потоке я читал, что изображение будет отправлять только, если сокет закрывается. Так что, поскольку я не хочу, чтобы основной сокет закрывался, или я теряю соединение, я создал другой сокет, который временно откроется, чтобы передать только скриншот.

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

На стороне сервера я добавил еще одну строку, которая создает образ локально только для устранения неполадок, если что-то идет до конца.

Заранее спасибо

ответ

3

Вы предполагаете, что read() заполняет буфер. Ничего в спецификации, которая так говорит. Попробуйте это:

int size = in.readInt(); 
byte[] imageAr = new byte[size]; 
in.readFully(imageAr); 

readInt() и readFully()являются гарантированно получить правильный размер, или потерпеть неудачу в попытке.

Вы также испытываете трудности с отправкой. Попробуйте это:

out.writeInt(size); 
out.write(baos.toByteArray()); 
out.close(); 

Обратите внимание, что перед тем flush()close() является излишним, но вы должны закрыть поток самый наружный выходной вокруг сокета, а не гнездо, чтобы получить его автоматически очищено.

Фактически, когда вы закрываете соединение после каждого изображения, вы можете избавиться от слов размера и байтов ввода-вывода и просто сделать ImageIO.read/write непосредственно из/в сокет. Это сэкономит много памяти.

+0

Я определенно получаю намного лучший результат от этого изменения.Я фактически сохранил «размер» в отправляющей стороне как массив байтов и «размер» на считывающем конце, а также получил большую часть экрана, но правая сторона и нижняя часть экрана были зафиксированы. Вероятно, это связано с тем, что я программировал удаленно с помощью RDP. Большое спасибо! – xR34P3Rx

+0

Я бы все же удалил слово size и поток массива байтов из-за пространственных и временных затрат. Не усложняйте простые вещи. – EJP

+0

хе-хе ... @EJP, могу я что-то спросить? out.writeInt (размер); out.write (baos.toByteArray()); out.close(); подходит для меня. если я не получил значение размера, ... откуда я его получил? размер int изображения или что-то еще? – gumuruh

Смежные вопросы