这个问题源自this one,我试图将图像数据从孩子发送到父母。在这种情况下,问题在于使用了缓冲和非缓冲读取功能。您可以在此问题的底部找到旧问题的工作代码。
现在,我尝试将图像从父进程发送到子进程(通过从父进程调用popen
生成),以显示iamge。
该图像是灰度png
图像。它使用OpenCV库打开,并使用同一库的imencode
函数进行编码。因此,将所得的编码数据存储到类型为std::vector
的{{1}}结构中,即以下代码中的uchar
向量。
为简单起见,图像的大小被硬编码在变量img
中的child中。这用于分配存储接收数据的内存。分配如下:
img_size
父级使用 u_char *buf = (u_char*)malloc(img_size*sizeof(u_char));
将编码数据(即向量img
中包含的数据)写入FILE*
返回的popen
流中,而子级则读取数据fwrite
使用fread
文件描述符的转换结果作为FILE*
:
STDIN_FILENO
数据写入是在while循环内的块FILE * fp = fdopen(STDIN_FILENO, "r");
个字节中执行的,而数据读取是在两次调用4096
中进行读取的(我知道这很丑陋,但是会有所改变)。
编写循环如下:
fread
while (written<img.size())
{
//bytes to send: 4096 or the remaining ones if less than 4096
toWrite = BUFLEN < (img.size()-written) ? BUFLEN : (img.size()-written);
//total bytes that have been sent until now
written += toWrite*fwrite ( img.data()+written, toWrite, 1, f );
printf("written: %ld\n", written);
}
将指针返回向量结构内部使用的数组中第一个元素。
img.data()
存储到现在为止已写入的字节数,它用作索引。
written
返回实际已写入的块数(每个块大小为fwrite
个字节),该块数用于更新toWrite
。
数据读取非常相似,它由以下行执行(written
初始化为bytes2Copy
):
4096
//read all possible bytes in blocks of 4096 until less than 4096 bytes remain
elRead = fread ( buf, bytes2Copy, img_size/bytes2Copy, fp);
total_bytes_read += elRead*bytes2Copy;
bytes2Copy = img_size-total_bytes_read; //now less than 4096 bytes remain
printf("child received %ld\n", total_bytes_read);
//read remaining bytes
elRead = fread ( buf+total_bytes_read, bytes2Copy, 1, fp);
是存储接收到的数据的数组。 buf
是bytes2Copy
(即BUFLEN
),还是最后一个数据块的剩余数据(例如,如果总字节为4096
,则在{{1} 1}}个字节,应该是5000
的另一个块。)
请考虑以下示例。以下是使用4096
5000-4096
和上面打开的过程对应于以下内容:
popen
父级读取图像,对其进行编码,然后发送编码后的图像数据。
孩子以#include <stdlib.h>
#include <unistd.h>//read
#include "opencv2/opencv.hpp"
#include <iostream>
#include <sys/wait.h>
#include "opencv2/opencv.hpp"
#define BUFLEN 4096
using namespace cv;
int main(int argc, char *argv[])
{
int status;
Mat frame;
std::vector<uchar> img;
//read image as grayscale
frame = imread("/home/path/img/test.png",0);
//encode image and put data into the vector buf
imencode(".png",frame, img);
//send the total size of vector to parent
size_t toWrite = 0;
size_t written= 0;
FILE * f = popen("/home/path/childProcess", "w");
printf("forked\n");
while (written<img.size())
{
//send the current block of data
toWrite = BUFLEN < (img.size()-written) ? BUFLEN : (img.size()-written);
//written += write(STDOUT_FILENO, buf.data()+written, toWrite);
written += toWrite*fwrite ( img.data()+written, toWrite, 1, f );
printf("written: %ld\n", written);
}
wait(&status);
return 0;
}
为单位读取数据。但是,在第二次调用#include <stdlib.h>
#include <unistd.h>
#include "opencv2/opencv.hpp"
#include <iostream>
#include <time.h>
#define BUFLEN 4096
int main(int argc, char *argv[])
{
cv::Mat frame;
size_t img_size = 115715;
u_char *buf = (u_char*)malloc(img_size*sizeof(u_char));
size_t total_bytes_read = 0;
size_t elRead =0;
size_t bytes2Copy = BUFLEN;
FILE * fp = fdopen(STDIN_FILENO, "r");
elRead = fread ( buf, bytes2Copy, img_size/bytes2Copy, fp);
total_bytes_read += elRead*bytes2Copy;
bytes2Copy = img_size-total_bytes_read;
printf("child received %ld\n", total_bytes_read);
elRead = fread ( buf+total_bytes_read, bytes2Copy, 1, fp); //sostituire 1
total_bytes_read += elRead*bytes2Copy;//bytes_read_tihs_loop;
printf("child received %ld\n", total_bytes_read);
cv::namedWindow( "win", cv::WINDOW_AUTOSIZE );
frame = cv::imdecode(cv::Mat(1,total_bytes_read,0, buf), 0);
cv::imshow("win", frame);
cv::waitKey(0);
return 0;
}
时,其中缺少少于4096
个字节,它将尝试仅读取丢失的字节:在我的情况下,第二次对fread()
的调用应读为{{1} }个字节(4096
)。在第二个调用中,尽管父级发送了(或至少似乎发送了)所有数据,但它什么也没读。
frad
为什么不读取所有丢失的字节?
在我尝试对图像进行解码时可能也会出错,因此也将不胜感激。
请注意,在回答了原始问题之后,我设法正确地将数据从孩子发送到了父母(另一个方向)。 有效的代码如下:
父母:
1027
孩子:
115715%4096