2

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

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

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

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

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

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

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

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

这是我的代码:

服务器:

主文件

#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 );
}

客户:

主文件

#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;
    }
}
4

1 回答 1

0
  1. You are miscounting your frames. You must increment the frame counter after the mTcpSocket->bytesAvailable() < blockSize test! That's the source of your non-problem: it works OK, but you miscount the frames. That's also why it "works better" on Linux: the network stack there is buffering the data differently, giving you less signals.

  2. You must limit the amount of memory on the wire (buffered) on the server end. Otherwise, as you correctly noticed, you'll run out of memory. See my other answer for an example of how to do it.

  3. You're never freeing the memory you malloc() in the receiver. Be aware that you should expect to consume 35 megabytes of RAM per second if the server really sends at 40ms intervals. The receiver may well get bogged down very quickly by that memory leak. That's probably the source of the trouble.

  4. What is that QDataStream for? You're not using a datastream to send the image, and there's no use for it on the receiving end either.

于 2012-06-18T10:57:06.243 回答