简体   繁体   English

通过套接字将屏幕快照从Java发送到CPP-接收图像问题

[英]Sending screenshot from Java to CPP over socket - Issue receiving image

Java (server): Java(服务器):

take screenshot method 采取截图方法

    //Take screenshot of active application
    robot.keyPress(KeyEvent.VK_CONTROL);
    robot.keyPress(KeyEvent.VK_ALT);
    robot.keyPress(KeyEvent.VK_PRINTSCREEN);
    robot.delay(5);
    robot.keyRelease(KeyEvent.VK_PRINTSCREEN);
    robot.keyRelease(KeyEvent.VK_CONTROL);
    robot.keyRelease(KeyEvent.VK_ALT);

    Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
    flavors = cb.getAvailableDataFlavors();
    for (DataFlavor flavor : flavors) {
        if (flavor.toString().indexOf("java.awt.Image") <= 0) {
            continue;
        }
        i[0] = (Image) cb.getData(flavor);
    }
    robot.delay(50);

    bi = new BufferedImage(i[0].getWidth(null), i[0].getHeight(null),
            BufferedImage.TYPE_BYTE_GRAY); // keep buffered image as gray scale

    // resize image since I don't need large res
    resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_BYTE_GRAY);
    g = resizedImage.createGraphics();
    g.drawImage(i[0], 0, 0,IMG_WIDTH, IMG_HEIGHT, null);

    g.dispose();

    ByteArrayOutputStream baos = new ByteArrayOutputStream(); // <-- This is irrelevant!
    ImageIO.write(resizedImage, "jpg", baos);
    baos.flush();
    byte[] imageInByte = baos.toByteArray();
    baos.close();
    return imageInByte;

open socket and send image 打开插座并发送图像

    byte[] screenShot = SaveScreenshot();
    ServerSocket serverSocket = null; 
    Socket slientSocket = null;
    Socket clientSocket = null;
    try {
        serverSocket = new ServerSocket(4447);
        clientSocket = serverSocket.accept();

OutputStreamWriter(clientSocket.getOutputStream())); OutputStreamWriter(clientSocket.getOutputStream()));

        OutputStream out = clientSocket.getOutputStream();
        ByteArrayOutputStream bScrn = new ByteArrayOutputStream();

        out.write((Integer.toString(screenShot.length)).getBytes());
        out.write(screenShot,0,screenShot.length);

        serverSocket.close();
        clientSocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

CPP (client): CPP(客户):

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>
#include <cstddef>
#include <cstdlib>
#include <strings.h>


using namespace std;
int main()
{
int sockfd; // socket file descriptor 
int portno; // port number
struct sockaddr_in serv_addr;
struct hostent *server;

char ip[] = "127.0.0.1"; // ip of server
portno = 4447; // port number

sockfd = socket(AF_INET, SOCK_STREAM, 0); // generate file descriptor 
if (sockfd < 0)
    perror("ERROR opening socket");

server = gethostbyname(ip); //the ip address (or server name) of the listening server.
if (server == NULL) {
    fprintf(stderr,"ERROR, no such host\n");
    exit(0);
}

bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);

if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
    perror("ERROR connecting");

char rbuff[256];
//int rbuff;
int rbytes;

rbytes = recv(sockfd, rbuff, sizeof(rbuff), 0); // similar to read(), but return -1 if socket closed
rbuff[rbytes] = '\0'; // set null terminal
printf("Message: %s  %d\n", rbuff, atoi(rbuff));

unsigned char *ssByte = new unsigned char[atoi(rbuff)];
rbytes = recv(sockfd, ssByte, sizeof(ssByte), 0);

FILE *fp=fopen("/home/chen/Pictures/recv.jpeg","w");
fwrite(ssByte,sizeof(ssByte),1, fp);

return 0;
}
  1. Java opens socket Java打开套接字
  2. Cpp connects Cpp连接
  3. Java sends ByteArray size (int) Java发送ByteArray大小(int)
  4. Cpp creates unsigned char* array that size Cpp创建该大小的无符号char *数组
  5. Java sends the image Java发送图像
  6. Cpp attempts to save CPP尝试保存

Made sure in Java, saved the Image and all goes well. 确保使用Java保存图像并一切正常。 Checked that the size of the Image I receive from the Java into Cpp is identical between the two. 检查我从Java接收到Cpp的映像的大小在两者之间是否相同。

In the Java application, if I direct the ImageIO.write function to 在Java应用程序中,如果我将ImageIO.write函数定向到

new File("/dir/test.jpg") 新文件(“ /dir/test.jpg”)

I receive a proper working jpg. 我收到适当的工作jpg。

That leads me to think the issue isn't with the jpg "header" but somewhere else. 这使我认为问题不在于jpg“ header”,而在于其他地方。

Thanks for any help given! 感谢您提供的任何帮助!

** EDIT #1 ** Changed the receive (cpp) to the following code: **编辑#1 **将接收(cpp)更改为以下代码:

do {
     rbytes = recv(sockfd, ssByte, sizeof(ssByte), 0);
     if ( rbytes > 0 )
         printf("Bytes received: %d\n", rbytes);
     else if ( rbytes == 0 )
         printf("Connection closed\n");
     else
         printf("recv failed\n");
} while( rbytes > 0 );

What I see is that every incoming message is of 8 Bytes maximum (the last is 3 Bytes). 我看到的是,每个传入消息的最大长度为8字节(最后一个为3字节)。 I'll try to combine the inputs and see if they build up a properly working JPG, question is if I can force the Java to send at larger packet sizes - especially since this is over localhost and not over the NIC. 我将尝试合并输入,并查看它们是否建立了可以正常工作的JPG,问题是我是否可以强制Java以更大的数据包大小进行发送-尤其是因为这是通过localhost而不是通过NIC进行的。

** EDIT 2 - Alternative solution ** **编辑2-替代解决方案**

In addition to the solution by Alnitak, you can also do: 除了Alnitak的解决方案,您还可以执行以下操作:

This will keep the whole stream into byte array and then dump into file (in case you need to do further manipulation before saving). 这会将整个流保留在字节数组中,然后转储到文件中(以防在保存之前需要做进一步的处理)。

unsigned char ssByte[atoi(rbuff)];
int last = 0;

if ( rbytes > 0 ) { // rbytes is from the last call, to make sure socket still open and the image isn't zero size
        do {
             rbytes = recv(sockfd, &ssByte[last], 4096, 0);
             if ( rbytes > 0 ){
                //printf("Bytes received: %d\n", rbytes);
                last += rbytes;
             }
             else if ( rbytes == 0 )
                 printf("Connection closed\n");
             else
                 printf("recv failed\n");
        } while( rbytes > 0 );

        printf("Image: %d\n", last);

        FILE *fp=fopen("/home/chen/Pictures/recv.jpg","w");
        fwrite(ssByte,sizeof(unsigned char),last, fp);
        fclose(fp);
}
return 0;

Thanks to all that helped! 感谢所有的帮助!

Your problem is that sizeof ssByte is not the size of the array, it's the size of that pointer. 您的问题是sizeof ssByte 不是数组的大小,而是指针的大小。 There's no problem with your network transmission or packet sizes - on TCP streams that's normally controlled by the O/S and not the application. 网络传输或数据包大小没有问题-在通常由O / S而非应用程序控制的TCP流上。

In any event, it would be more common to create a modest-sized byte array of fixed size, and then use a while() loop to read chunks of that much data at a time, finishing once you have the specified number of bytes. 无论如何,创建固定大小的中等大小的字节数组,然后使用while()循环一次读取大量数据的块,并在具有指定数量的字节后完成,会更常见。

You can also then write that data to the file as it's read. 然后,您还可以在读取数据时将该数据write文件。 I'd also note that there's no good reason to use <stdio> for writing the file since there's no need to buffer or format any output. 我还要指出,没有必要使用<stdio>来写文件,因为不需要缓冲或格式化任何输出。 It would be simpler to just use open() and write() : 仅使用open()write()会更简单:

unsigned char buf[4096];  // nb: no "new", and sizeof *does* work on arrays

int filefd = open(..., O_WRONLY | O_CREAT);
while (rbytes > 0) {
    int n = recv(sockfd, buf, sizeof buf, 0);
    if (n > 0) {
        int w = write(filefd, buf, n); // assumes file writes are all or nothing
        if (w < 0) {
            // error
        }
        rbytes -= n;
    } else if (n == 0) {
        // closed
    } else {
        // error
    }
}

close(filefd);
close(sockfd);

// no need to deallocate buf as it's on the stack, not the heap

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM