2

QTcpSocket に基づいて 2 つのテスト アプリケーションを作成しようとしています。これは、(圧縮されていない) 画像をストリーミングするサーバーと、それらを受信するクライアントです。

私のコードは主に Qts Fortune Client Example およびFortune Server Exampleから取られています。私はすべてのグイを切り取った。接続を開いて幸運を送信してからすぐに閉じる代わりに、サーバーは接続を開いたままにし、画像を継続的にストリーミングします。クライアントは QTcpSocket からイメージを読み取り、破棄します。

私が送信している画像は 800x600 RGB (=1440000 バイト) で、許可されている限り送信しています。画像は送信されるたびにファイルから読み取られ、圧縮は使用していません。

サーバーは画像を送信しているようです。しかし、クライアントは1秒あたり1〜4フレームとゆっくりと受信し、時々データを受信して​​いないように見えるため、サーバーが大量のメモリを使用する原因になります(クライアントがサーバーが書き込み中です)。

サーバーとクライアントを異なるマシンで実行してみましたが、両方を 1 つのマシンで実行しましたが、どちらのセットアップでも同じ問題が発生します。

私のアプリケーションを Linux マシンで実行すると、クライアントははるかに高い速度で画像を受信します (1 秒あたり 14 フレームだったと考えてください)。クライアントは、サーバーが書き込むのと同じ速さで読み取ることができるようです。

この問題に光を当てるのを手伝ってくれる人はいますか?

  1. データ転送を高速化するにはどうすればよいですか? (圧縮を使用しない場合)
  2. サーバーが書き込んでいるのと同じ速さでクライアントを読み取らせるにはどうすればよいですか?
  3. これを 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();
}

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

クライアント.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. フレームのカウントを間違えています。mTcpSocket->bytesAvailable() < blockSizeテスト後にフレーム カウンターをインクリメントする必要があります。それが問題の原因です。問題なく動作しますが、フレームのカウントを間違えています。それが、Linux で「うまく機能する」理由でもあります。ネットワーク スタックは、データを別の方法でバッファリングするため、シグナルが少なくなります。

  2. サーバー側でワイヤ上の(バッファリングされた)メモリの量を制限する必要があります。そうしないと、お気付きのように、メモリ不足になります。それを行う方法の例については、私の他の回答を参照してください。

  3. malloc()レシーバーでメモリを解放することはありません。サーバーが実際に 40 ミリ秒間隔で送信する場合、毎秒 35 メガバイトの RAM を消費することが予想されることに注意してください。レシーバーは、そのメモリ リークによってすぐに行き詰まる可能性があります。それがおそらくトラブルの元です。

  4. それは何QDataStreamのためですか?画像を送信するためにデータストリームを使用しておらず、受信側でも使用できません。

于 2012-06-18T10:57:06.243 に答える