gpt4 book ai didi

c++ - 如何在Qt中读取下一个数据包

转载 作者:行者123 更新时间:2023-11-30 03:51:50 25 4
gpt4 key购买 nike

我的客户端设置如下:客户端首先发送一个数据包,其中包含要从套接字读取的实际数据的长度。然后客户端自己发送实际数据。 (我在实际发送数据之前预先设置了数据包长度)。

我想知道如何在 Qt Creator 中读取下一个数据包。我收到一条错误消息,提示未找到此类插槽:MyThread::readPacket (int)。我做错了什么?

(如果我读取的字节数错误,请忽略该部分)

我的服务器端代码如下:

#include "thread.h"
#include <QDebug>
#include "DataSetProtos.pb.h"
MyThread::MyThread(qintptr ID, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
}

void MyThread::run()
{
// thread starts here
qDebug() << " Thread started";

socket = new QTcpSocket();

// set the ID
if(!socket->setSocketDescriptor(this->socketDescriptor))
{
// something's wrong, we just emit a signal
emit error(socket->error());
return;
}

// connect socket and signal
// note - Qt::DirectConnection is used because it's multithreaded
// This makes the slot to be invoked immediately, when the signal is emitted.

connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));

// We'll have multiple clients, we want to know which is which
qDebug() << socketDescriptor << " Client connected";

// make this thread a loop,
// thread will stay alive so that signal/slot to function properly
// not dropped out in the middle when thread dies

exec();
}

void MyThread::readyRead()
{
// get the information
char* buffer = new char[SIZE];
int iResult= socket->read(buffer, SIZE);

connect(socket,SIGNAL(readyRead()), this, SLOT(readPacket(iResult)), Qt::DirectConnection);
}

void MyThread::readPacket(int bufferLength)
{
char *buffer = new char[bufferLength];
int iResult = socket->read(buffer, bufferLength);
printf("\n Read 2 : %d", iResult);

}

void MyThread::Print(Visualization::PacketData packet)
{
printf("\n\nPacket Name : %s", packet.name());
printf("\n Packet length : %d ", packet.length());
}

void MyThread::disconnected()
{
qDebug() << socketDescriptor << " Disconnected";


socket->deleteLater();
exit(0);
}

我的thread.h文件如下:

#ifndef THREAD_H
#define THREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QDebug>
#include "DataSetProtos.pb.h"

#define SIZE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(qintptr ID, QObject *parent = 0);

void run();

signals:
void error(QTcpSocket::SocketError socketerror);

public slots:
void readyRead();
void readPacket( int bufferLength);
void disconnected();
void Print( Visualization::PacketData packet );

private:
QTcpSocket *socket;
qintptr socketDescriptor;
};

#endif // THREAD_H

最佳答案

正如 MrPickles 指出的那样,您让自己很难过。但是,您不需要一直更改数据格式。您只需要在不需要时停止尝试使用线程。 Qt 中几乎没有任何东西需要使用线程,除了繁重的数据处理或类似的事情。绝对不是基本的网络 I/O。

我有一个应用程序正在与消息长度前缀的 protobufs 通信。这是我的 onReadyRead 实现的要点,更改了一些细节并删除了不必要的内容:

void ProtobufMessageReceiver::onReadyRead()
{
//Some maximum size of a message to protect from malformed
//packets or bugs. This value should be above the size of the largest
//protobuf message you ever expect to receive.
static const uint32_t MAX_ALLOWED_SIZE = 1024 * 1024; //1MB

uint32_t msg_size;
while ( m_socket->bytesAvailable() >= sizeof(msg_size) )
{
m_socket->peek(reinterpret_cast<char*>(&msg_size), sizeof(msg_size));

//OK, we have read in a 32-bit message size, now verify that
//it is valid before we try to read that many bytes on the socket

if ( msg_size > MAX_ALLOWED_SIZE )
{
//You might throw an exception here or do some other error
//handling. Like most Qt code, though, this app doesn't
//use exceptions, so we handle a malformed packet by just
//closing the socket. In a real app you'd probably at least
//want to do some logging here, as this should be a very
//abnormal case and signifies a bug on the sending end.
m_socket->close();
break;
}

//Now check to see if we have that many bytes available to read in.
//If we do, we have at least one full message waiting to process, if not,
//we'll process the message on the next call to onReadyRead.
if ( m_socket->bytesAvailable() >= sizeof(msgSize) + msgSize )
{
m_socket->read(reinterpret_cast<char*>(&msg_size), sizeof(msg_size));

QScopedArrayPointer<char> buffer(new char[msgSize]);
m_socket->read(&buffer[0], msgSize);
processMessage(buffer, msgSize);
}
else
{
break;
}
}
}

processMessage 函数现在将始终处理一个单一的、完全有效的 protobuf 流,可以使用 parseFromArray 对其进行解码。 (在这个例子中,我们可能会使用一个 protobuf Union Type 在一个流中交错几种不同的类型)。请注意,因为不能保证 onReadyRead 会为每个 protobuf 消息调用一次,所以在其中设置 while 循环非常重要。无论您使用的是 Qt 还是使用套接字的其他方式,情况都是如此,因为 TCP 只是一个字节流,并不划定消息边界。毕竟,这就是我们甚至必须首先处理长度前缀的全部原因。

关于c++ - 如何在Qt中读取下一个数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31079605/

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