c++ - 写入QTcpSocket并不总是在相反的QTcpSocket上发出readyRead信号

标签 c++ qt sockets qtcpsocket qtcpserver

过去 5 天我一直在这个问题上,我知道如何继续。

概述:

我有一个客户端 UI,它与数据处理程序库交互,并且数据处理程序库利用网络管理器 库,这就是我的问题所在。

更多信息

首先,QT 提供了 QTcpServer ( Fortune Server ) 和 QTcpSocket ( Fortune Client ) 之间交互的基本示例。

因此,我将这段代码实现为我自己的一个非常基本的示例,它工作起来就像一个魅力,没有任何问题。

我自己的命运改编clientserver供记录(基本)

快速解释:

服务器应用程序运行,单击启动服务器,然后在客户端,在字段中输入文本,然后单击连接到服务器,然后显示文本,简单!

问题:

将上面的代码实现到我的网络管理器库中,不会触发 QTcpSocket::readyRead()在上面的服务器应用程序中。

它连接到服务器,其中 QTcpServer::newConnection()正如预期的那样,在客户端写入套接字之后立即被触发,但服务器套接字上的readyRead()不会触发,但在给出的示例中它会触发。

注意:服务器-客户端应用程序示例和我当前的应用程序使用相同的端口ip地址,并且服务器也在运行。

更多信息:

从上面的代码中,我直接从客户端复制过来。仅更改/修改了两件事:

  • 发送到服务器的字符串
  • 方法的返回类型

这已复制到我的 network manager::write() 方法中。运行我的应用程序时,QMainWindow 的实例通过 data handler 类传递,并创建继承 network manager 类的实例QObject 并实现 Q_OBJECT 宏。

代码示例:

//client_UI 类(片段):

data_mananger *dman = new data_mananger(this);                //this -> QMainWindow
ReturnObject r = dman->NET_AuthenticateUser_GetToken(Query);

//data_manager 库(片段)

data_mananger::data_mananger(QObject *_parent) :
    parent(_parent)
{}

ReturnObject data_mananger::NET_AuthenticateUser_GetToken(QString Query){
    //Query like "AUTH;U=xyz@a;P=1234"

    //convert query string to char
        QByteArray ba = Query.toLatin1();

    //send query and get QList return
        ReturnCode rCode = networkManager.write(ba);

    //...
}

//netman 库(片段)

//.h

class NETMANSHARED_EXPORT netman : public QObject
{
    Q_OBJECT
public
    netman();
    netman(QObject *_parent);
    //...

private:
    QTcpSocket *tcp_con;
    //...
};

//cpp

netman::netman(QObject *_parent) :
    parent(_parent)
{
    tcp_con = new QTcpSocket(parent);
}

        return;
    }
    serverIP.setAddress(serverInfo.addresses().first().toIPv4Address());
}

ReturnCode netman::write(QByteArray message, int portNumber){

    tcp_con->connectToHost(QHostAddress("127.0.0.1"), 5000);

    if (!tcp_con->waitForConnected())
    {
        qDebug(log_lib_netman_err) << "Unable to connect to server";
        return ReturnCode::FailedConnecting;
    }

    if (!tcp_con->isValid()) {
        qDebug(log_lib_netman_err) << "tcp socket invalid";
        return ReturnCode::SocketError;
    }

    if (!tcp_con->isOpen()) {
        qDebug(log_lib_netman_err) << "tcp socket not open";
        return ReturnCode::SocketError;
    }

    //    QByteArray block(message);
    QByteArray block;
    QDataStream out(&block,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);

    out << QString("Hello world");

    if (!tcp_con->write(block)){
        qDebug(log_lib_netman_err) << "Unable to send data to server";
        return ReturnCode::WriteFailed;
    }
    else{
        qDebug(log_lib_netman_info) << "Data block sent";
        return ReturnCode::SentSuccess;
    }
}

结论:

客户端的核心代码已经全部实现了,但是我不明白为什么会出现这个错误。

我非常感谢帮助/建议!

最佳答案

tcp_con->flush() 语句添加到写入函数的末尾。

为什么/如何运作

您没有在接收器中收到 readyRead 信号,因为写入的数据被缓冲到套接字中,但实际上并未“通过线路”传输。 flush() 命令导致缓冲区被传输。来自 the docs

This function writes as much as possible from the internal write buffer to the underlying network socket, without blocking. If any data was written, this function returns true; otherwise false is returned.

你怎么知道

就我而言,在串行端口和刷新方面有很多经验/挫折。这相当于“你重新启动了吗?”在套接字调试工具箱中。

如果其他一切工作正常,您可能不必刷新,但它是特定于应用程序的,取决于套接字的生命周期、TCP 窗口大小、套接字选项设置以及各种其他因素。也就是说,我总是刷新,因为我喜欢完全控制我的套接字,并且我想确保数据在我想要的时候传输。我不认为这是黑客攻击,但在某些情况下,它可能表明存在其他问题。再次强调,具体应用。

为什么缓冲区可能不会自行刷新?

我很确定在 Fortune 服务器示例中不需要刷新,因为它们在 sendFortune() 函数末尾以及来自 Qt documentationdisconnectFromHost 中。 :

Attempts to close the socket. If there is pending data waiting to be written, QAbstractSocket will enter ClosingState and wait until all data has been written.

如果套接字也被破坏,它也会断开连接,但从我所看到的代码来看,你也没有这样做,并且缓冲区未满,所以可能没有任何东西真正刺激缓冲区刷新自身.

其他原因可能是:

  • 流控制不会返回到事件循环(阻塞调用等),因此永远不会执行缓冲区刷新。
  • Transmit 发生在循环内部,看起来它会退出(例如 while(dataToTransmit)),但实际上条件永远不会变为 false,这会导致事件循环被阻塞。
  • Nagles 算法:缓冲区在刷新自身之前可能会等待更多数据,以保持较高的网络吞吐量。您可以通过设置 QAbstractSocket::LowDelayOption 来禁用此功能,但这可能会对您的吞吐量产生不利影响...它通常用于对延迟敏感的应用程序。

关于c++ - 写入QTcpSocket并不总是在相反的QTcpSocket上发出readyRead信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42074728/

相关文章:

c++ - Visual Studio 2019 : How to use Platform Toolset v140_xp?

c++ - 模板函数多态性

javascript - 套接字挂断错误与nodejs

java - 在 Java 中通过套接字发送文件

java - 如何在 Android 客户端和 Java 服务器之间创建安全的 SSL 连接?

c++ - 当程序删除时崩溃时如何调试?

c++ - 在 DirectX 11 中将文本绘制为二维纹理?

c++ - 读取 .vtk 文件

qt - 如何创建尊重 Material 样式颜色的自定义 QML 控件?

c++ - 是否有可用于 OpenAL 的 Qt 包装器