Qt UDP Socket:如何连续发送请求并获得响应
Qt UDP Socket: How to continuously send request and get response
我有一个QT UDP客户端和服务器程序
服务器代码
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 );
}
客户代码
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
如果我在 BREAKPOINT#2 上设置断点而不是单个断点
"Received From Server: "
出现在控制台上,所有已发送的信息立即出现。
所有这些意味着所有发送请求都同时发生,然后在客户端接收。
我担心的是
我应该能够对一个请求得到一个响应,否则如果我的程序 运行 连续 24 或 48 小时持续发送请求,那么客户端将不会得到一个响应!
我还需要将每个响应实时映射到相应的请求,这不会发生
编辑下方()
即使我不循环发送消息而是单独发送,行为也是相同的。我在下面稍微更改了代码
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: "
消息。
核心应用程序是单线程的,您可以在同一个循环内发送所有消息。因此,即使您可能已经在两者之间收到响应,Qt 应用程序也只会在返回到事件循环(在 exec() 中)后处理它们。所以这是预料之中的,也很简单。
如果您想在中间接收消息,您可以:
- 使用 QTimer 将您的消息发送给 space 它们并在其间设置事件循环 运行,但这只是更复杂而已。
- 在消息之间手动调用
QEventLoop().processEvents();
,但我不特别推荐这样做。
- 多线程你的应用程序(QThread,QtConcurrent),但是这对于正确处理并发性来说很棘手,只有在你有繁重的处理时才值得。
如果您需要将每个请求映射到一个答案,我认为您需要在消息中的某处添加一个 ID (int) 以识别它们。但是如果你开始在一条消息中包含多个内容,我真的建议在两端使用 QDataStream
正确地序列化和反序列化你的数据,否则它很快就会变得混乱和复杂。
一个好的方法通常是创建一个 class 来保存您的消息并序列化它们,例如:
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();
}
我有一个QT UDP客户端和服务器程序
服务器代码
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 );
}
客户代码
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
如果我在 BREAKPOINT#2 上设置断点而不是单个断点
"Received From Server: "
出现在控制台上,所有已发送的信息立即出现。
所有这些意味着所有发送请求都同时发生,然后在客户端接收。
我担心的是
我应该能够对一个请求得到一个响应,否则如果我的程序 运行 连续 24 或 48 小时持续发送请求,那么客户端将不会得到一个响应!
我还需要将每个响应实时映射到相应的请求,这不会发生
编辑下方()
即使我不循环发送消息而是单独发送,行为也是相同的。我在下面稍微更改了代码
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: "
消息。
核心应用程序是单线程的,您可以在同一个循环内发送所有消息。因此,即使您可能已经在两者之间收到响应,Qt 应用程序也只会在返回到事件循环(在 exec() 中)后处理它们。所以这是预料之中的,也很简单。
如果您想在中间接收消息,您可以:
- 使用 QTimer 将您的消息发送给 space 它们并在其间设置事件循环 运行,但这只是更复杂而已。
- 在消息之间手动调用
QEventLoop().processEvents();
,但我不特别推荐这样做。 - 多线程你的应用程序(QThread,QtConcurrent),但是这对于正确处理并发性来说很棘手,只有在你有繁重的处理时才值得。
如果您需要将每个请求映射到一个答案,我认为您需要在消息中的某处添加一个 ID (int) 以识别它们。但是如果你开始在一条消息中包含多个内容,我真的建议在两端使用 QDataStream
正确地序列化和反序列化你的数据,否则它很快就会变得混乱和复杂。
一个好的方法通常是创建一个 class 来保存您的消息并序列化它们,例如:
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();
}