Qt UDP套接字:如何连续发送请求并获得响应



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

SERVER代码

main.cpp

#include <QCoreApplication>
#include "myserver.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyServer myserver;
return a.exec();
}

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

CLIENT代码

main.cpp

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

myclient.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

如果我在断点#2上设置断点"Received From Server: "出现在控制台上,所有发送的信息同时出现。所有这些意味着所有发送请求同时发生,然后接收到的请求发生在客户端。

我关心的是

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

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

编辑Below((

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

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

在断点#3和断点#4处添加断点不会导致任何"Received From Server: "消息。

核心应用程序是单线程的,您可以在同一个循环中发送所有消息。因此,即使您可能已经收到介于两者之间的响应,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();
}

最新更新