通过套接字将Java中的屏幕截图发送到CPP - 发出接收图像

时间:2015-11-20 09:01:36

标签: java c++ image sockets jpeg

Java(服务器):

采取截屏方式

    //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;

打开套接字并发送图片

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

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(客户):

#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打开套接字
  2. Cpp连接
  3. Java发送ByteArray size(int)
  4. Cpp创建大小
  5. 的unsigned char *数组
  6. Java发送图像
  7. Cpp尝试保存
  8. 确保在Java中保存了图像,一切顺利。 检查我从Java接收到Cpp的Image的大小是否相同。

    在Java应用程序中,如果我将ImageIO.write函数指向

      

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

    我收到了一个合适的工作jpg。

    这让我觉得问题不在于jpg“标题”,而是在其他地方。

    感谢您提供任何帮助!

    **编辑#1 ** 将receive(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 );
    

    我看到的是每个传入的消息最多为8个字节(最后一个是3个字节)。我将尝试组合输入并查看它们是否构建了正常工作的JPG,问题是我是否可以强制Java以更大的数据包大小发送 - 特别是因为这是通过localhost而不是通过NIC。

    **编辑2 - 替代解决方案**

    除了Alnitak的解决方案,您还可以:

    这会将整个流保存为字节数组,然后转储到文件中(如果您需要在保存之前进行进一步的操作)。

    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;
    

    感谢所有帮助!

1 个答案:

答案 0 :(得分:1)

你的问题是sizeof ssByte 不是数组的大小,它是指针的大小。您的网络传输或数据包大小没有问题 - 在通常由操作系统而不是应用程序控制的TCP流上。

无论如何,创建一个固定大小的适度大小的字节数组会更常见,然后使用while()循环一次读取那么多数据的块,一旦你拥有了指定的字节数。

然后,您还可以将write数据传输到文件中。我还注意到没有充分的理由使用<stdio>来编写文件,因为不需要缓冲或格式化任何输出。使用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