0

我有一个 QT UDP 客户端和服务器程序

服务器代码

主文件

#include <QCoreApplication>
#include "myserver.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    MyServer myserver;

    return a.exec();
}

我的服务器.cpp

#include "myserver.h"
#include <iostream>

MyServer::MyServer(QObject *parent)
{
    socket = new QUdpSocket(this);
    clientSocket = new QUdpSocket(this);
    socket->bind(QHostAddress::LocalHost,1234);
 
    connect(socket,SIGNAL(readyRead()),this,SLOT(processClientRequest()));
    qDebug()<<"=============================";
    qDebug()<<"     Server Started     ";
    qDebug()<<"=============================";
}

void MyServer::processClientRequest()
{
    qDebug()<<"processClientRequest()";
    QByteArray buffer;
    buffer.resize(socket->pendingDatagramSize());

    QHostAddress sender;
    quint16 senderPort;
    socket->readDatagram(buffer.data(),buffer.size(),&sender,&senderPort);
    qDebug()<<"Message:"<<buffer;
    
    std::string lineString = buffer.toStdString();

    double response = <some double value here>;//This value gets generated on the server using business some logic
    std::cout<<"response:"<<response<<endl;
    sendResponseDatagram(target);

}

void MyServer::sendResponseDatagram(double target)
{
    QString prefix="Response:";
    QString doubleStr = QString::number(target);
    QString word = prefix + doubleStr;
    QByteArray buffer;
    QHostAddress sender;
    buffer=word.toUtf8();
    clientSocket->writeDatagram(buffer.data(), QHostAddress::LocalHost, 5678 );
}

客户代码

主文件

#include <QCoreApplication>
#include "myclient.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    MyClient client;

    const int len = 50;

    std::string lineArray[len];
    client.readFileIntoLineArray("MyInputFile.csv",lineArray);

    client.sendBulkArrayDataToServer(lineArray,len);
    qDebug()<<"Here";

    return a.exec();
}

我的客户端.cpp

#include "myclient.h"
#include <string>
#include <iostream>
#include <fstream>

using namespace std;

MyClient::MyClient(QObject *parent)
{
    mySocket = new QUdpSocket(this);
    serverSocket = new QUdpSocket(this);
    mySocket->bind(QHostAddress::LocalHost,5678);
    connect(mySocket,SIGNAL(readyRead()),this,SLOT(readDatagramsReceivedFromServer()));
}


void MyClient::sendBulkArrayDataToServer(std::string lineArray[],int length)
{
    for(int i=0;i<length;i++)
    {
        std::string line = lineArray[i];
        QString word=QString::fromStdString(line);
        QByteArray buffer;
        QHostAddress sender;
        buffer=word.toUtf8();
        serverSocket->writeDatagram(buffer.data(), QHostAddress::LocalHost, 1234 );
        qDebug()<<"Sent to server";//---->***BREAKPOINT#1***
    }
}

void MyClient::readFileIntoLineArray(std::string filepath,std::string lineArray[])
{
    int i=0;
    try
    {
        std::string line;
        ifstream file(filepath);

        if(file.is_open())
        {
            while(getline(file,line))
            {
                lineArray[i]=line;
                i++;

            }
            file.close();
        }
        else std::cout << "not able to open file";
    }
    catch (ifstream::failure e)
    {
        cout << e.what() << endl;
    }

}


void MyClient::readDatagramsReceivedFromServer()
{

    while (mySocket->hasPendingDatagrams()) {
        QByteArray buffer;
        buffer.resize(mySocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        mySocket->readDatagram(buffer.data(), buffer.size(),&sender, &senderPort);
        qDebug()<<"Received From Server:"<<buffer;//----->***BREAKPOINT#2***
    }
}
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Sent to server
Here
Received From Server: "Response:0.5"
Received From Server: "Response:2.7"
Received From Server: "Response:1.6"
Received From Server: "Response:0"
Received From Server: "Response:2.9"
Received From Server: "Response:3"
Received From Server: "Response:7"
Received From Server: "Response:2.6"
Received From Server: "Response:1"
Received From Server: "Response:2.1"
Received From Server: "Response:0"
Received From Server: "Response:1.6"
Received From Server: "Response:5"
Received From Server: "Response:4"
Received From Server: "Response:8"
Received From Server: "Response:9"
Received From Server: "Response:10"
Received From Server: "Response:11"
Received From Server: "Response:21"
Received From Server: "Response:3"

我期待客户端控制台输出应该如下所示

Sent to server
Received From Server: "Response:0.5"
Sent to server
Received From Server: "Response:2.7"
Sent to server
Received From Server: "Response:1.6"
Sent to server
Received From Server: "Response:0"
Sent to server
...
...
..

另外,如果我在调试模式下运行并将断点放在 BREAKPOINT#1 上(请参见上文),我得到的只是

Sent to server
Sent to server
Sent to server

如果我在 BREAKPOINT#2 上放置断点, "Received From Server: "则控制台上不会出现一个断点,并且所有发送的内容都会立即出现。所有这些意味着所有发送请求同时发生,然后在客户端接收。

我担心的是

  1. 我应该能够为一个请求获得一个响应,否则如果我的程序连续运行 24 或 48 小时并不断发送请求,那么客户端将不会得到一个响应!

  2. 我还需要将每个响应与相应的请求实时映射,这不会发生

在下面编辑()

即使我不循环发送消息而是单独发送,行为也是相同的。我在下面稍微更改了代码

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    MyClient client;
    
    const int len = 50;
    
    std::string lineArray[len];
    client.readFileIntoLineArray("MyInputFile.csv",lineArray);
    //client.sendBulkArrayDataToServer(lineArray,len);
    client.sendOneSampleDataToServer(lineArray,1);
    client.sendOneSampleDataToServer(lineArray,2);//----->***BREAKPOINT#3***
    client.sendOneSampleDataToServer(lineArray,3);//----->***BREAKPOINT#4***
    qDebug()<<"Here";

    return a.exec();
}


void MyClient::sendOneSampleDataToServer(std::string lineArray[],int index)
{
        std::string line = lineArray[index];
        QString word=QString::fromStdString(line);
        QByteArray buffer;
        QHostAddress sender;
        buffer=word.toUtf8();
        serverSocket->writeDatagram(buffer.data(), QHostAddress::LocalHost, 1234 );
        qDebug()<<"Sent to server";

}

在 BREAKPOINT#3 和 BREAKPOINT#4 添加断点不会产生任何"Received From Server: "消息。

4

1 回答 1

1

核心应用程序是单线程的,您可以在同一个循环中发送所有消息。因此,即使您可能已经在两者之间收到响应,Qt 应用程序也只会在返回事件循环(在 exec() 中)时处理它们。所以这是意料之中的,也很简单。

当您想在两者之间接收消息时,您可以:

  • 使用 QTimer 发送您的消息以将它们隔开一点,并让事件循环在其间运行,但这只是更复杂而已。
  • 在消息之间手动调用QEventLoop().processEvents();,但我不特别推荐。
  • 多线程您的应用程序(QThread、QtConcurrent),但这很难正确处理并发,只有在处理繁重的情况下才值得。

如果您需要将每个请求映射到答案,我认为您需要在消息中的某处添加一个 ID (int) 以识别它们。但是,如果您开始在一条消息中包含多个内容,我真的建议您QDataStream在两端正确地序列化和反序列化您的数据,否则它很快就会变得混乱和复杂。

一个好方法通常是创建一个类来保存消息并序列化它们,例如:

class Message
{
public:
    explicit Message(int id, const QString& text);
    QByteArray toBinary();
    bool fromBinary(const QByteArray& binary);

private:
    int id;
    QString text;
}

QByteArray Message::toBinary()
{
    QByteArray binary;
    QDataStream stream(&binary, QIODevice::WriteOnly);
    // here: set endianness, precision & co for the stream
    stream << id;
    stream << text;
    return binary;
}

bool Message::fromBinary(const QByteArray& binary)
{
    QDataStream stream(binary);
    // here: set endianness, precision & co for the stream
    stream >> id;
    stream >> text;
    return (stream.status == QDataStream::Ok) && stream.atEnd();
}
于 2020-12-03T08:12:22.690 回答