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

时间:2012-06-18 10:29:31

标签: c++ windows qt tcp streaming

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

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

我发送的图像是800x600 RGB(= 1440000字节),我经常发送它,因为我被允许。每次发送图像之前都会从文件中读取图像,而我没有使用任何压缩。

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

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

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

任何人都可以帮助解决这个问题吗?

  1. 如何加快数据传输速度? (不使用压缩)
  2. 如何让客户端以服务器写入的速度快速读取?
  3. 如何在Windows机器上保持稳定? (没有突然停顿...)单击客户端的控制台窗口有时似乎“唤醒”应用程序btw。 ^^
  4. 这是我的代码:

    服务器:

    的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;
    }
    

    Server.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_ */
    

    Server.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();
    }
    

    Client.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_ */
    

    Client.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;
        }
    }
    

1 个答案:

答案 0 :(得分:0)

  1. 您错误地计算了自己的画面。您必须在mTcpSocket->bytesAvailable() < blockSize测试后递增帧计数器!这是你的非问题的根源:它工作正常,但你错误计算帧。这也是它在Linux上“工作得更好”的原因:网络堆栈以不同的方式缓冲数据,为您提供更少的信号。

  2. 您必须限制服务器端的 (缓冲)内存量。否则,正如您所注意到的那样,您将耗尽内存。有关如何操作的示例,请参阅我的other answer

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

  4. QDataStream是什么意思?您没有使用数据流来发送图像,并且在接收端也没有用它。