【问题标题】:Low TCP Connection performance problem in QTQT 中的 TCP 连接性能低下问题
【发布时间】:2019-06-10 17:51:30
【问题描述】:

我正在从事一个图像处理项目,我从相机获取帧并通过使用 Qt 库构建的 TCP 连接发送帧。 我正在尝试发送 24 帧,但是当我运行程序时,只有 13 帧(大约)到达。

我使用信号和插槽开始与按钮的连接,当连接建立时,计时器开始,我在一秒钟内发送 24 帧。

编辑:我切换到单连接服务器,但它对性能影响不大,有时帧也会损坏(?)(我只看到空白帧)

tcpsender.cpp

#include "tcpsender.h"
#include "ui_tcpsender.h"

#include <QtWidgets>
#include <QtNetwork>
#include <QtCore>
#include <QDebug>
#include <QBuffer>
#include <QDataStream>

#define XRES 640
#define YRES 480


TCPSender::TCPSender(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TCPSender)
{
    ui->setupUi(this);
    statusLabel = new QLabel(tr("Ready to send frames on port 6667"));
    statusLabel->setWordWrap(true);
    startButton = new QPushButton(tr("&Start"));
    auto quitButton = new QPushButton(tr("&Quit"));
    auto buttonBox = new QDialogButtonBox;
    buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

    socket = new QTcpSocket(this);
    connect(startButton, &QPushButton::clicked, this, &TCPSender::startConnection);
    connect(quitButton, &QPushButton::clicked, this, &TCPSender::close);
    connect(socket, SIGNAL(connected()), SLOT(startSending()));
    connect(&timer, &QTimer::timeout, this, &TCPSender::sendFrame);

    auto mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Broadcast Sender"));
    camera = new Camera("/dev/video0", XRES, YRES);

    time = QTime::currentTime();

}

TCPSender::~TCPSender()
{
    delete ui;
}

bool TCPSender::startConnection()
{
    if (socket->state() == QAbstractSocket::UnconnectedState)
    {

        socket->connectToHost(ui->lineEdit->text(), 6667, QIODevice::WriteOnly);
        return socket->waitForConnected();

    }
}

void TCPSender::startSending()
{
    startButton->setEnabled(false);
    timer.start(1000/24);
    qDebug()<<"Timer start";
}

bool TCPSender::sendFrame()
{
    if(socket->state()==QAbstractSocket::ConnectedState){
        auto frame = camera->frame();

        image = new QImage(frame.data,XRES,YRES,QImage::Format_RGB888);
        QImage im = image->convertToFormat(QImage::Format_Grayscale8);
        QByteArray ba;
        QBuffer buffer(&ba);
        im.save(&buffer,"BMP");

        qDebug()<<"writing socket";
        socket->write(ba);

        int speed = time.msecsTo(QTime::currentTime());
        time = QTime::currentTime();
        speed = 1000*300/speed;
        ui->label->setText(QString("%1 kb/s").arg(speed));
        delete image;

   }

}

receiver.cpp

#include "reciever.h"    
#include <QBuffer>
#include <QTcpSocket>
#include <QImage>
#include <QDebug>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <unistd.h>

Reciever::Reciever(QObject* parent): QTcpServer(parent)
{
    connect(this, SIGNAL(newConnection()), this, SLOT(addConnection()));
}

void Reciever::addConnection()
{
    qDebug()<<"Adding Connection";
    QTcpSocket* connection = nextPendingConnection();
    connect(connection, SIGNAL(readyRead()),
            this, SLOT(receiveImage()));

    connections.append(connection);
    QBuffer* buffer = new QBuffer(this);
    buffer->open(QIODevice::ReadWrite);
    buffers.insert(connection, buffer);

}

void Reciever::receiveImage()
{
    qDebug()<<"RECIEVE";
    QTcpSocket* socket = static_cast<QTcpSocket*>(sender());
    QBuffer* buffer = buffers.value(socket);
    qint64 bytes = buffer->write(socket->readAll());   
    emit sendBuffer(buffer,bytes);
}

【问题讨论】:

  • TCP 流没有结构。您可以在任意数量的readAll 调用中接收数据。如果你想要一个“框架”序列,你需要自己添加那个结构。
  • @molbdnilo 你能给我看一些关于你所说的结构的例子吗?我的意思是我已经可以发送帧了,唯一的问题是帧率低。

标签: c++ qt sockets tcp


【解决方案1】:

您在每个计时器滴答声中调用startConnection();。这具有在关闭和重新打开连接之间交替的效果。

  • 您可以在sendFrame 中删除对startConnection 的调用,保持TCP 连接打开。

  • 或者你的计时器滴答率加倍到timer.start(1000/48);

【讨论】:

  • 但我正在检查是否与if(socket-&gt;state()==QAbstractSocket::ConnectedState) 有任何活动连接,对吗?那么我如何在每个计时器滴答声中调用startConnection()?我在这里错过了什么吗?
  • @onurcevik 为什么需要为每个帧连接和断开连接?使用TCP,您通常会连接一次,在有数据要交换时保持连接打开,然后断开连接。
  • 每次调用 startConnection() 实际上都会打开和关闭连接,这就解释了为什么你会得到一半的帧。 startButton::clicked 已经连接到 startConnection(),发送每个 Frame 后不需要连接/断开连接。
  • @G.M.我试图在这里实现服务器-客户端系统:stackoverflow.com/questions/20546750/… 我无法读取套接字来缓冲单个连接。但我可以与 QBuffer* buffer = buffers.value(socket); 建立多个连接。如何从套接字读取单个连接的缓冲区?
  • @onurcevik 听起来您遇到的基本问题正如@molbdnilo 所描述的那样——您希望服务器的一次写入恰好对应于客户端上的一次读取。您引用的问题确实提供了答案,但是,如果您不满意使用它,您可能希望使用QWebSocketServer 框架而不是QTcpServer。这样你就可以简单地通过`QWebSocket::sendBinaryMessage发送每一帧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多