通过套接字将屏幕截图从 Java 发送到 CPP - 发出接收图像
Sending screenshot from Java to CPP over socket - Issue receiving image
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] = '[=14=]'; // 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;
}
- Java 打开套接字
- Cpp 连接
- Java发送字节数组大小(int)
- Cpp 创建大小为
的 unsigned char* 数组
- Java发送图片
- Cpp 尝试保存
确保在 Java 中保存图像,一切顺利。
检查我从 Java 接收到 Cpp 的图像大小在两者之间是相同的。
在 Java 应用程序中,如果我将 ImageIO.write 函数指向
new File("/dir/test.jpg")
我收到了一个正常工作的 jpg。
这使我认为问题不在于 jpg "header",而在于其他地方。
感谢您的帮助!
** 编辑 #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 );
我看到的是每条传入消息最大为 8 字节(最后一条为 3 字节)。我将尝试组合输入并查看它们是否构建了一个正常工作的 JPG,问题是我是否可以强制 Java 以更大的数据包大小发送 - 特别是因为这是通过本地主机而不是通过 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;
感谢所有的帮助!
你的问题是 sizeof ssByte
是 而不是 数组的大小,它是那个指针的大小。您的网络传输或数据包大小没有问题 - 在通常由 O/S 而不是应用程序控制的 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
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] = '[=14=]'; // 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;
}
- Java 打开套接字
- Cpp 连接
- Java发送字节数组大小(int)
- Cpp 创建大小为 的 unsigned char* 数组
- Java发送图片
- Cpp 尝试保存
确保在 Java 中保存图像,一切顺利。 检查我从 Java 接收到 Cpp 的图像大小在两者之间是相同的。
在 Java 应用程序中,如果我将 ImageIO.write 函数指向
new File("/dir/test.jpg")
我收到了一个正常工作的 jpg。
这使我认为问题不在于 jpg "header",而在于其他地方。
感谢您的帮助!
** 编辑 #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 );
我看到的是每条传入消息最大为 8 字节(最后一条为 3 字节)。我将尝试组合输入并查看它们是否构建了一个正常工作的 JPG,问题是我是否可以强制 Java 以更大的数据包大小发送 - 特别是因为这是通过本地主机而不是通过 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;
感谢所有的帮助!
你的问题是 sizeof ssByte
是 而不是 数组的大小,它是那个指针的大小。您的网络传输或数据包大小没有问题 - 在通常由 O/S 而不是应用程序控制的 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