简体   繁体   English

Qt客户端服务器应用程序“发送图像”出现问题

[英]Qt Client-server app, “send image” having problems

I am trying to send an image ( OpenCV Mat ) from client to server over a QDataStream . 我正在尝试通过QDataStream从客户端向服务器发送图像( OpenCV Mat )。 The first item is an int, the size of the buffer. 第一项是int,即缓冲区的大小。 It works for 10 to 15 images, then the server reads the first int a random number (usual ~2^30) which causes the app to crash. 它可以处理10到15张图片,然后服务器读取第一个int随机数(通常〜2 ^ 30),这会导致应用崩溃。 This is the client side, in a loop (the images come from webcam with period 500ms): 这是客户端,处于一个循环中(图像来自摄像头,周期为500ms):

//1) encode to jpg
 cv::vector<uchar> buf;
 cv::imencode(".jpg", *mat, buf);

 //2) write to buffer
 QByteArray buffer;
 QDataStream out(&buffer, QIODevice::WriteOnly);
 out << int(0); // save place for an int which represents the buffer size

 for(cv::vector<uchar>::iterator it = buf.begin(); it != buf.end(); ++it)
 {
  out << *it; //write each byte
 }

 out.device()->seek(0); //write the buffer size
 out << buffer.size();
 qDebug() << "Sent " << buffer.size() << "bytes";

 qint64 bytesSent = socket->write(buffer);
 if(bytesSent < buffer.size())
 {
  if(bytesSent != -1)
  {
   qDebug() << "Transmit Error! Sent " << bytesSent << " out of " << buffer.size();
  }
  else
  {
   qDebug() << socket->errorString();
  }
 }

Server side: 服务器端:

QDataStream in(socket);
 int msgSize = -1;

 //first read the size as an int
 if(socket->bytesAvailable())
 {
  in >> msgSize;
 }

 qDebug() << "Read image size: " << msgSize << "bytes";
 //wait until all bytes all available
 while(socket->bytesAvailable() < ( qint64 ) ( ( qint64 )msgSize - sizeof(int) ) )
 {
  if(!socket->waitForReadyRead())
  {
   qDebug() << "Disconnected: " << socket->errorString();
   socket->disconnectFromHost();
   break;
  }
 }
 qDebug() << "Bytes recieved: " << msgSize;


 QByteArray ba;
 quint8 byte;
 for(int i = 0; i < msgSize - 1; ++i)
 {
  in >> byte;
  ba.append(byte);
 }
        cv::Mat imgbuf = cv::Mat(FRAME_WIDTH, FRAME_HEIGHT, CV_8UC3, ba.data());
 cv::Mat matImg = cv::imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);

Both sockets are QTcpSocket . 两个套接字都是QTcpSocket

Output example: 输出示例:

The server side: 

Read image size: 67551 bytes 
Bytes recieved: 67551 
Read image size: 56924 bytes 
Bytes recieved: 56924 
Read image size: 70027 bytes 
Bytes recieved: 70027 
Read image size: -2046830337 bytes 
Bytes recieved: -2046830337 
Read image size: -536866742 bytes 
Bytes recieved: -536866742 
Read image size: 1179207168 bytes 

At this point it tries to read 1179207168 bytes. 

The client side: 
Sent 67551 bytes 
Sent 56924 bytes 
Sent 70027 bytes 
Sent 70277 bytes 
Sent 85633 bytes 
Sent 65155 bytes 
etc ... 

Only the first three are successful. 只有前三个成功。

First of all, I don't believe you need QDataStream for this task. 首先,我认为您不需要QDataStream来完成此任务。 QDataStream is meant for serializing/deserializing Qt types, and is specific to the version of Qt you are using. QDataStream用于序列化/反序列化Qt类型,并且特定于您使用的Qt版本。 Since you simply want to write uchar's over the network, you can iterate through your cv::vector directly, and write those bytes directly over the wire (in fact, you don't need the intermediary QByteArray either since you already have the byteLength with your original vector). 由于您只是想通过网络编写uchar,因此您可以直接在cv :: vector中进行迭代,然后直接在网络上写入这些字节(实际上,您不需要中间的QByteArray,因为您已经有了byteLength您的原始向量)。

However, you CAN use QDataStream (since you're working with very basic types that are not likely to change between QDataStream versions), and since you started that way, I'll provide an answer accordingly 但是,您可以使用QDataStream(因为您使用的是非常基本的类型,这些类型在QDataStream版本之间可能不会更改),并且由于您是从这种方式开始的,因此我将相应地提供答案

This would look more like (client side): 这看起来更像(客户端):

// 1) encode to jpg
cv::vector<uchar> buf;
cv::imencode(".jpg", *mat, buf);

// 2) write to buffer, your 'protocol' assumes buffer length first, then the data.
// REMEMBER: QDataStream operates on -any- QIODevice, so no need for the extra buffer here
QDataStream out(socket, QIODevice::WriteOnly);
out << buf.size();

cv::vector<uchar>::const_iterator it;
cv::vector<uchar>::const_iterator itEnd = buf.end();
for (it = buf.begin(); it != itEnd; ++it)
    out << *it;

server side: 服务器端:

QDataStream in(socket, QIODevice::ReadOnly);
cv::vector<uchar> buf;
socket->waitForReadyRead();

qint64 bytesRead = 0;
qint64 size;
in >> size;

buf.reserve(size);
while (buf.size() < size) {
    if (!socket->bytesAvailable())
        socket->waitForReadyRead();

    qint8 byte;
    in >> byte;
    buf.push_back(byte);
}

cv::Mat imgbuf = cv::Mat(FRAME_WIDTH, FRAME_HEIGHT, CV_8UC3, buf);
cv::Mat matImg = cv::imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);

NOTE: this is all off the cuff, it could very well not compile and there is certainly a much more efficient way of doing this, but I think it gives you the basic idea of how you could go about fixing your existing code 注意:这一切都可以解决,它很可能无法编译,并且肯定有一种更有效的方法,但是我认为它为您提供了如何修复现有代码的基本思路

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

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