gpt4 book ai didi

c++ - Qt,从客户端向服务器发送多种数据类型+数据流

转载 作者:行者123 更新时间:2023-11-30 01:42:44 30 4
gpt4 key购买 nike

我有一个基于 Qt客户端/服务器应用程序,使用 QTcpServer 和 QTcpSocket,我设法建立连接并在客户端和客户端之间来回发送一些数据服务器。客户端向服务器发送多种类型的数据(字符串、整数、文件和实时音频流),因为我的服务器实现了单个数据输入 SLOT (readyRead()):

connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));

我不知道如何区分所有这些接收到的数据并分别调用服务器中的正确函数。

Example (in the server):
- if I receive string => call function showData(QString data);
- if I receive file => call function saveFile(QFile file);
- if I receive audio stream => play audio stream
- ...

服务器:

void Server::newClientConnection()
{
QTcpSocket *socket = server->nextPendingConnection();

connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
//...
}

void Server::readyRead()
{
QTcpSocket *clientSocket = qobject_cast<QTcpSocket *>(sender());
if (clientSocket == 0) {
return;
}

QDataStream in(clientSocket);

if (sizeMessageClient == 0)
{
if (clientSocket->bytesAvailable() < (int)sizeof(quint16)){
return;
}
in >> sizeMessageClient;
}

if (clientSocket->bytesAvailable() < sizeMessageClient) {
return;
}

sizeMessageClient = 0;

in >> data;
/*
I don't know the type of the received data !!

- if I receive string => call function showData(QString data);
- if I receive file => call function saveFile(QFile file);
- if I receive audio stream => play audio stream
- ...
*/

}

客户:

Client::Client()
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));

sizeMessageServer = 0;
}


void Client::readyRead()
{
QDataStream in(socket);
if (sizeMessageServer == 0)
{
if (socket->bytesAvailable() < (int)sizeof(quint16)) {
return;
}

in >> sizeMessageServer;
}

if (socket->bytesAvailable() < sizeMessageServer) {
return;
}

int messageReceived;
in >> messageReceived;
messageReceived = static_cast<int>(messageReceived);

sizeMessageServer = 0;

switch(messageReceived)
{
case 1:
qDebug() << "send a File";
sendFile();
break;
case 2:
qDebug() << "send a string data";
sendStringData();
break;
case 3:
qDebug() << "stream audio to the server";
streamAudioToServer();
break;
case n:
// ...
}
}

我不是在寻找一个完整的解决方案,我只是在寻找一些正确方向的指导。

最佳答案

您的协议(protocol)的实现没有完全利用 Qt 5.7 中的 QDataStream。现在看起来可能是这样的 - 它可以非常简单。

首先,让我们定义我们知道的请求:

enum class Req : quint32 {
Unknown, String, File
};
Q_DECLARE_METATYPE(Req)
QDataStream & operator<<(QDataStream & ds, Req req) {
return ds << (quint32)req;
}
QDataStream & operator>>(QDataStream & ds, Req & req) {
quint32 val;
ds >> val;
if (ds.status() == QDataStream::Ok)
req = Req(val);
return ds;
}

拥有交易 RAII 助手也很方便。

struct Transaction {
QDataStream & stream;
Transaction(QDataStream & stream) : stream{stream} {
stream.startTransaction();
}
~Transaction() {
stream.commitTransaction();
}
bool ok() {
return stream.status() == QDataStream::Ok;
}
};

客户端接收来自服务器的请求并发出需要用数据回复的信号。使用客户端的代码会对这些信号使用react,并通过调用匹配的插槽进行回复。例如

void clientUser(Client & client) {
QObject::connect(&client, &Client::needString, &client, [&]{
client.sendString(QStringLiteral{"You got string!"});
});

和:

class Client : public QObject {
Q_OBJECT
QIODevice & m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
Transaction tr{m_str};
Req req;
m_str >> req;
if (!tr.ok()) return;
if (req == Req::String)
emit needString();
else if (req == Req::File) {
QString fileName;
m_str >> fileName;
if (!tr.ok()) return;
emit needFile(fileName);
}
else emit unknownRequest(req);
}
public:
Client(QIODevice & dev) : m_dev{dev} {
connect(&m_dev, &QIODevice::readyRead, this, &Client::onReadyRead);
}
Q_SIGNAL void unknownRequest(Req);
Q_SIGNAL void needString();
Q_SIGNAL void needFile(const QString & fileName);
Q_SLOT void sendString(const QString & str) {
m_str << Req::String << str;
}
Q_SLOT void sendFile(const QString & fileName, const QByteArray & data) {
m_str << Req::File << fileName << data;
}
};

服务器非常相似。它的用户通过 request 槽向客户端发送请求。一旦服务器从客户端收到回复,它就会通过 has 信号表明它:

class Server : public QObject {
Q_OBJECT
QIODevice & m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
Transaction tr{m_str};
Req req;
m_str >> req;
if (!tr.ok()) return;
if (req == Req::String) {
QString str;
m_str >> str;
if (!tr.ok()) return;
emit hasString(str);
}
else if (req == Req::File) {
QString fileName;
QByteArray data;
m_str >> fileName >> data;
if (!tr.ok()) return;
emit hasFile(fileName, data);
}
else emit hasUnknownRequest(req);
}
public:
Server(QIODevice & dev) : m_dev{dev} {
connect(&m_dev, &QIODevice::readyRead, this, &Server::onReadyRead);
}
Q_SIGNAL void hasUnknownRequest(Req);
Q_SIGNAL void hasString(const QString &);
Q_SIGNAL void hasFile(const QString & name, const QByteArray &);
Q_SLOT void requestString() {
m_str << Req::String;
}
Q_SLOT void requestFile(const QString & name) {
m_str << Req::File << name;
}
};

关于c++ - Qt,从客户端向服务器发送多种数据类型+数据流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39144556/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com