写入QTcpSocket并不总是在相反的QTcpSocket

时间:2017-02-06 18:27:56

标签: c++ qt sockets qtcpsocket qtcpserver

过去5天我一直坚持这一点,我没有想法如何继续。

概述:

我有client UIdata handler库互动,data handler库使用network manager库,这是我的问题所在。

更多信息

首先,QT提供了QTcpServerFortune Server)和QTcpSocketFortune Client)之间互动的基本示例。

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

我自己的财富clientserver适应记录(基本)

快速说明:

运行服务器应用程序,单击start server,然后在客户端,在字段中输入文本并单击connect to server,显示文本,简单!

问题:

将上述代码实施到我的network manager库中,不会触发上面服务器应用程序中的QTcpSocket::readyRead()

它连接到server,其中QTcpServer::newConnection()被触发,正如预期的那样,client写入套接字,但服务器套接字上的readyRead()然而,在给定的例子中,它不会发射。

注意:port应用程序示例和我当前的应用程序中使用了相同的ip addressserver-client,并且服务器也在运行。

更多信息:

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

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

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

代码示例:

// client_UI Class(摘录):

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;
    }
}

结论:

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

我非常感谢帮助/建议!

1 个答案:

答案 0 :(得分:2)

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

为什么/如何运作

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

  

此函数尽可能从内部写入写入   缓冲到底层网络套接字,没有阻塞。如有任何数据   写了,这个函数返回true;否则返回false。

你怎么知道

在我的情况下,串口和刷新有很多经验/挫折。这相当于“你重启了吗?”在套接字调试工具箱中。

如果其他一切正常,您可能不必flush,但它是特定于应用程序的类型,取决于套接字的生命周期,TCP窗口大小,套接字选项设置和各种其他因素。也就是说,我总是刷新,因为我喜欢完全控制我的套接字,我想确保数据在我希望的时候传输。我不认为这是一个黑客,但在某些情况下,它可能表明一些其他问题。同样,特定于应用程序。

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

我非常确定fortune服务器示例中不需要刷新,因为disconnectFromHost函数末尾的sendFortune()以及Qt documentation

  

尝试关闭套接字。如果有待处理的待处理数据   写完后,QAbstractSocket将进入ClosingState并等到所有   数据已写完。

套接字如果被销毁也会断开连接,但是从我所看到的代码中你也没有这样做,并且缓冲区未满,所以可能没有什么东西实际上刺激缓冲区冲洗自己

其他原因可能是:

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