从 QTcpSocket 读取数据时出现问题

发布于 2024-11-29 14:16:16 字数 1663 浏览 0 评论 0原文

我修改了 Qt 示例中的 线程财富服务器。 客户端连接到服务器,然后发送标头进行身份验证。

tcpSocket = new QTcpSocket();
tcpSocket->connectToHost(addr, port);
QByteArray block = "someheader";
int x = tcpSocket->write(block);
qDebug() << x;

客户端在这里看起来没问题,qDebug 打印了block 的实际大小。

在服务器端,我预定义了 incomingConnection 并为每个新连接启动线程。

void Server::incomingConnection(int socketDescriptor) {
    const QString &str = vec[qrand() % vec.size()];
    SpellThread *thread = new SpellThread(socketDescriptor, str);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    qDebug() << " -- incoming connection";
    thread->start();
}

我正在连接 sock 来检查是否有东西可读。 (sock 这里是 QTcpServer*

void SpellThread::run() {
    qDebug() << " -- in spellthread";
    connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes()));
    //....
    qDebug() << " -- end spellthread";
}

第一个问题是,当我从客户端发送数据时,readyRead 不会被触发。 (我在 checkBytes 中添加了调试消息) 消息是:

 -- incoming connection 
 -- in spellthread 
 -- end spellthread

虽然客户端打印了标头长度的实际大小。

第二个问题是 checkBytes 目前的设计非常糟糕。首先它检查标头是否正常并设置一个标志,然后获取消息的大小并设置另一个标志,最后获取真正的消息。这是非常笨拙的。我首先尝试转义信号并使用 sock->waitForReadyRead()。然而它总是返回 false。 (来自文档:“重新实现此函数以为自定义设备提供阻塞 API。默认实现不执行任何操作,并返回 false。”)。

那么如何在 Qt 中真正制作一个具有多个客户端和多个读/写的客户端/服务器应用程序呢?我真的想要一些建议来改进我的应用程序的设计并解决我当前的两个问题。

I've modified the threaded fortune-server from Qt examples.
The client connects to the server and then sends a header to authenticate.

tcpSocket = new QTcpSocket();
tcpSocket->connectToHost(addr, port);
QByteArray block = "someheader";
int x = tcpSocket->write(block);
qDebug() << x;

The client seems OK here and qDebug prints the actual size of block.

On the server side I've predefined incomingConnection and I start thread to each new connection.

void Server::incomingConnection(int socketDescriptor) {
    const QString &str = vec[qrand() % vec.size()];
    SpellThread *thread = new SpellThread(socketDescriptor, str);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    qDebug() << " -- incoming connection";
    thread->start();
}

I'm connecting sock to check is there something to read. (sock here is QTcpServer*)

void SpellThread::run() {
    qDebug() << " -- in spellthread";
    connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes()));
    //....
    qDebug() << " -- end spellthread";
}

The first problem is that when I'm sending data from the client, readyRead is not fired. (I've added debug message in checkBytes)
Messages are:

 -- incoming connection 
 -- in spellthread 
 -- end spellthread

Although the client prints the actual size of header length.

The second problem is that checkBytes currently is very bad-designed. First it checks is header OK and sets a flag, then it gets the size of message and sets another flag and finally it gets the real message. This is very clumsy. I first tried to escape signals and instead use sock->waitForReadyRead(). However it always returns false. (From the docs: "Reimplement this function to provide a blocking API for a custom device. The default implementation does nothing, and returns false.").

So how to really make a client/server application in Qt with multiple clients and multiple reads/writes? I really want suggestions to improve design of my application and to solve my current two problems.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

地狱即天堂 2024-12-06 14:16:16

如果不调用 QThread::exec() 来启动该线程/运行函数中的事件循环,则无法在线程中使用插槽或套接字信号。

由于您的 checkBytes 插槽属于 QThread,因此它不会由线程执行(有一篇关于 QThreads 的详细文章 此处

似乎已经是最接近的示例做你想做的就是网络聊天(特别是两个类服务器连接)。

----------
编辑

如果您需要使用线程(不带任何槽),QTcpSocket 对象必须与您调用 waitForReadyRead 的线程属于同一线程。例如,使用:

SpellThread::SpellThread(int socketDescriptor, const QString & str) {
    tcpSocket = new QTcpSocket(); // There should be no parent to be able
                                  // to move it to the thread
    tcpSocket->moveToThread(this);
    ...

或者通过在 run 函数内创建 QTcpSocket 对象,以便它自动属于该线程(在 Fortune 示例中对此进行了简要解释)。
如果您动态分配 QTcpSocket,并且由于它没有父级,您还应该手动删除它。

You can't use slots or socket signals with a thread without calling QThread::exec() to start an event loop within that thread/the run function.

Since your checkBytes slot belongs to QThread, it wouldn't be executed by the thread (there is a detailed article about QThreads here)

The closest example that seems to already do what you want is the Network Chat (particularly the two classes Server and Connection).

----------
Edit

If you need to use threads (without any slot), the QTcpSocket object must belongs to the same thread as the one where you call waitForReadyRead. For example, with:

SpellThread::SpellThread(int socketDescriptor, const QString & str) {
    tcpSocket = new QTcpSocket(); // There should be no parent to be able
                                  // to move it to the thread
    tcpSocket->moveToThread(this);
    ...

Or by creating the QTcpSocket object inside the run function so that it automatically belongs to that thread (it was briefly explained in the fortune example).
If you allocate the QTcpSocket dynamically, and because it won't have a parent, you should also delete it manually.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文