在 Windows 7 上通过 QTcpSocket 流式传输图像

Posted

技术标签:

【中文标题】在 Windows 7 上通过 QTcpSocket 流式传输图像【英文标题】:Streaming images over QTcpSocket on Windows 7 【发布时间】:2012-06-18 10:29:30 【问题描述】:

我正在尝试创建两个基于 QTcpSocket 的测试应用程序,一个传输(未压缩)图像的服务器和一个接收图像的客户端。

我的代码主要取自 Qts Fortune Client Example 和 Fortune Server Example。我已经删掉了所有的gui。我的服务器没有打开连接、发送财富然后立即关闭它,而是保持它打开并不断地流式传输我的图像。客户端只是从 QTcpSocket 中读取图像然后丢弃它们。

我发送的图像是 800x600 RGB(=1440000 字节),我会尽可能频繁地发送它。每次发送之前都会从文件中读取图像,并且我没有使用任何压缩。

服务器似乎正在按应有的方式发送图像。但是客户端接收它们的速度太慢,每秒 1-4 帧,而且有时似乎没有接收到任何数据,这反过来又导致我的服务器使用大量内存(因为客户端的读取速度不如服务器正在写入)。

我尝试在不同的机器上运行我的服务器和客户端,并且都在一台机器上,两种设置都会产生同样的问题。

在 Linux 机器上运行我的应用程序时,客户端以更高的速率接收图像(认为它是每秒 14 帧)。客户端似乎能够像服务器写入一样快地读取。

任何人都可以帮助阐明这个问题吗?

    如何加快数据传输速度? (不使用压缩) 如何让客户端的读取速度与服务器的写入速度一样快? 我怎样才能让它在我的 Windows 机器上保持稳定? (没有突然的停顿......)在客户端的控制台窗口中单击有时似乎会“唤醒”应用程序顺便说一句。 ^^

这是我的代码:

服务器:

main.cpp

#include <iostream>
#include <QCoreApplication>
#include "Server.h"

int main(int argc, char *argv[])
    QCoreApplication app(argc, argv);
    QString ipaddress = QString(argv[1]);
    int port = atoi(argv[2]);
    Server* server = new Server(ipaddress, port);
    int retVal = app.exec();
    return retVal;

服务器.h

#ifndef SERVER_H_
#define SERVER_H_

#include <QObject>

QT_BEGIN_NAMESPACE
class QTcpServer;
class QNetworkSession;
class QTcpSocket;
class QTimer;
QT_END_NAMESPACE

class Server : public QObject

    Q_OBJECT

public:
    Server(QString ipAddress, int port, QObject *parent = 0);

private slots:
    void newConnectionSlot();
    void sendSlot();

private:
    QTcpServer          *mTcpServer;
    QTcpSocket          *mTcpSocket;
    QTimer              *mSendTimer;
;

#endif /* SERVER_H_ */

服务器.cpp

#include "Server.h"
#include <iostream>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer>
#include <QDateTime>
#include <QSettings>
#include <highgui.h>

Server::Server(QString ipAddress, int port, QObject *parent) :
    QObject(parent), mTcpServer(0), mTcpSocket(0)

    mTcpServer = new QTcpServer(this);
    connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
    if (!mTcpServer->listen(QHostAddress(ipAddress), port)) 
        std::cout << "Unable to start the server: " << mTcpServer->errorString().toStdString() << std::endl;
        return;
    

    std::cout << "The server is running on\n\nIP: "<< ipAddress.toStdString()
            << "\nport: " << mTcpServer->serverPort() << "\n\nRun the Client now.\n" << std::endl;


void Server::newConnectionSlot()

    mTcpSocket = mTcpServer->nextPendingConnection();
    connect(mTcpSocket, SIGNAL(disconnected()),
            mTcpSocket, SLOT(deleteLater()));

    // setup timer to send data at a given interval
    mSendTimer = new QTimer(this);
    connect(mSendTimer, SIGNAL(timeout()),
            this, SLOT(sendSlot()));
    mSendTimer->start(40);


void Server::sendSlot()

    if(!mTcpSocket)
        return;

    //know that the image is this big
    int width = 800;
    int height = 600;
    int nChannels = 3;
    int depth = 8;
    qint64 blockSize = 1440000; //in bytes

    qint64 imagesInQue = mTcpSocket->bytesToWrite()/blockSize;
    int maxPendingImages = 25;
    if(imagesInQue > maxPendingImages)
    
        std::cout << "Dumping." << std::endl;
        return;
    

    //load image
    IplImage* img = cvLoadImage("pic1_24bit.bmp");
    if(!img)
        std::cout << "Error loading image " << std::endl;;

    //send data
    quint64 written = mTcpSocket->write(img->imageData, img->imageSize);

    //clean up
    cvReleaseImage( &img );

客户:

main.cpp

#include <iostream>
#include <QCoreApplication>

#include "Client.h"

int main(int argc, char *argv[])
    QCoreApplication app(argc, argv);
    QString ipaddress = QString(argv[1]);
    int port = atoi(argv[2]);
    Client* client = new Client(ipaddress, port);
    int retVal = app.exec();

客户端.h

#ifndef CLIENT_H_
#define CLIENT_H_

#include <QObject>
#include <QAbstractSocket>

QT_BEGIN_NAMESPACE
class QTcpSocket;
QT_END_NAMESPACE

class Client : public QObject

    Q_OBJECT
public:
    Client(QString ipAddress, int port, QObject *parent=0);

private slots:
    void readSlot();
    void displayErrorSlot(QAbstractSocket::SocketError);

private:
    QTcpSocket          *mTcpSocket;
    QString             mIpAddress;
    int                 mPort;
;

#endif /* CLIENT_H_ */

客户端.cpp

#include "Client.h"
#include <iostream>
#include <QTcpSocket>
#include <QSettings>
#include <QDateTime>

Client::Client(QString ipAddress, int port, QObject *parent):
    QObject(parent), mTcpSocket(0), mIpAddress(ipAddress), mPort(port)

    mTcpSocket = new QTcpSocket(this);
    connect(mTcpSocket, SIGNAL(readyRead()),
            this, SLOT(readSlot()));
    connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(displayErrorSlot(QAbstractSocket::SocketError)));

    std::cout << "Connecting to ip: " << mIpAddress.toStdString() << " port: " << mPort << std::endl;
    mTcpSocket->connectToHost(mIpAddress, mPort);


void Client::readSlot()

    static qint64 starttime = QDateTime::currentMSecsSinceEpoch();
    static int frames = 0;

    //know that the image is this big
    int width = 800;
    int height = 600;
    int nChannels = 3;
    int depth = 8;
    qint64 blockSize = 1440000; //in bytes

    if (mTcpSocket->bytesAvailable() < blockSize)
    
        return;
    
    frames++;

    char* data = (char*) malloc(blockSize+100);
    qint64 bytesRead = mTcpSocket->read(data, blockSize);

    free(data);

    //FPS
    if(frames % 100 == 0)
        float fps = frames/(QDateTime::currentMSecsSinceEpoch() - starttime);
        std::cout << "FPS: " << fps << std::endl;
    


void Client::displayErrorSlot(QAbstractSocket::SocketError socketError)

    switch (socketError) 
    case QAbstractSocket::RemoteHostClosedError:
        break;
    case QAbstractSocket::HostNotFoundError:
        std::cout << "The host was not found. Please check the "
                                    "host name and port settings."<< std::endl;
        break;
    case QAbstractSocket::ConnectionRefusedError:
        std::cout << "The connection was refused by the peer. "
                                    "Make sure the fortune server is running, "
                                    "and check that the host name and port "
                                    "settings are correct."<< std::endl;
        break;
    default:
        std::cout << "The following error occurred: " << mTcpSocket->errorString().toStdString() << std::endl;
        break;
    

【问题讨论】:

您是在同一台计算机上还是在网络上同时运行服务器和客户端程序?如果通过网络,该网络的速度是多少?服务器或客户端计算机是否在执行大量其他网络活动? 我尝试在同一台计算机上和通过网络运行它们,两种设置都给出了相同的结果。在网络上运行时没有很多网络活动。有点奇怪,两种设置都给出了相同的结果,对吧?为什么这在 Linux 上有效?是不是Tcp socket的Qt实现? 【参考方案1】:

    您计算错误帧数。在mTcpSocket-&gt;bytesAvailable() &lt; blockSize 测试之后,您必须增加帧计数器!这就是您的非问题的根源:它工作正常,但是您错误地计算了帧数。这也是它在 Linux 上“工作得更好”的原因:那里的网络堆栈以不同的方式缓冲数据,给你的信号更少。

    您必须限制服务器端线路上(缓冲)的内存量。否则,正如您正确注意到的那样,您将耗尽内存。请参阅我的other answer 了解如何操作的示例。

    你永远不会释放接收器中malloc() 的内存。请注意,如果服务器确实以 40 毫秒的间隔发送,您应该期望每秒消耗 35 兆字节的 RAM。接收器很可能会因为内存泄漏而很快陷入困境。这可能是问题的根源。

    QDataStream 是干什么用的?您没有使用数据流来发送图像,在接收端也没有任何用处。

【讨论】:

1.我同意这一点。问题是这是一个简单的例子,我试图在我的其他(更大和更复杂的)应用程序中找到问题,我有一个限制服务器端缓冲区的方案。我将更新我的示例代码。 2.我纠正了这个错误,谢谢。 3、QDataStream什么都没用,忘记删了,现在修好了。 没错,我现在修好了。现在可以正确计算帧数,这给了我 0 fps。 :P 但我仍然有一个问题,因为这实际上在 linux 上效果更好。在我的复杂应用程序中,我正在流式传输在服务器上实时显示的图像,在 Linux 上视频实际上是实时的,而在 Windows 上,视频冻结并开始转储帧。 是的,让我上了那个,帧数被乐观地计算了,duh :) 我会在下班后检查它,看看它为什么会这样。不应该。 我唯一能想到的是std::endl 控制台刷新需要很长时间。您能否将//FPS 块放入if (frame % 100 == 0) ... 测试中,看看是否有帮助? 刚刚测试了它(并编辑了代码),它根本没有帮助。 :( 服务器几乎一直在转储,客户端 fps 为 0。每 4 秒左右写入控制台。

以上是关于在 Windows 7 上通过 QTcpSocket 流式传输图像的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 7 上信任 Java 7 的自签名证书

在 Windows 7 上模拟

Process.Start() 在 Windows 7 上立即退出

访问被拒绝在 Windows 7 上运行 sn.exe

在 Windows 7 上安装 Postgres for PHP(64 位)

我无法在我的系统 windows 7 32 位上的 XAMPP 上启动 Apache