没有 QTcpSocket 接收

Posted

技术标签:

【中文标题】没有 QTcpSocket 接收【英文标题】:No reception w/ QTcpSocket 【发布时间】:2018-03-13 23:30:15 【问题描述】:

我到处寻找示例,但似乎找不到解决方案。

问题

所以:我有一个名为 DataReceiver 的接收类。基本上,我只想从 localhost (127.0.0.1) 网络上的 TCP 套接字接收数据。似乎我可以用这个套接字编写(我用 Wireshark 软件检查过),但看起来程序没有收到任何东西。

我在 onDataReceived QT SLOT 中放置了一个 qDebug() 语句。这个插槽似乎不会在任何时候触发。我尝试手动编辑 mTcpSocket->readyRead() QT SIGNAL,并且正确调用了插槽,这意味着没有发出信号,因为 QTcpSocket 没有收到任何东西(或者至少我是这样)。

我的电脑是带有 macOS High Sierra 的 Mac。我扫描了开放的端口,发现 51470 和 50911 是开放的。这些是我测试的端口。

DataReceiver 类

这个类的代码如下:

datareceiver.h:

class DataReceiver : QObject

    Q_OBJECT

public:
    // Con/Destructors
    explicit DataReceiver(QObject *parent = nullptr);
    explicit DataReceiver(const QString &pSourceAddress,
                          const unsigned int &pSourcePort,
                          QObject *parent = nullptr);
    ~DataReceiver();

    // Network Management
    bool connectToHost(void);

    // Getters
    QVector<float> *getData(void) const;
    QTcpSocket *getTcpSocket(void) const;
    QString getSourceAddress(void) const;
    unsigned int getSourcePort(void) const;

    // Setters
    void setData(const QVector<float> *pData);
    void setSourceAddress(const QString &pSourceAddress);
    void setSourcePort(const unsigned int &pSourcePort);

signals:

public slots:
    void onConnect();
    void onDisconnect();
    void onBytesWritten(qint64 bytes);
    void onDataReceived();

private slots:

private:
    void decodeData(const QByteArray &pMessage);

    QTcpSocket *mTcpSocket;
    QString mSourceAddress;
    unsigned int mSourcePort;

    const unsigned int mDataSize = 30;
    QVector<float> *mData;
;

以及实现:datareceiver.cpp

// Con/Destructors
DataReceiver::DataReceiver(QObject *parent) :
    QObject(parent),
    mTcpSocket(new QTcpSocket(this)),
    mSourceAddress("127.0.0.1"),
    mSourcePort(51470),
    mData(new QVector<float>)

    for( unsigned int i = 0; i < mDataSize; i++)
        mData->append(.0);


DataReceiver::DataReceiver(const QString &pSourceAddress,
                      const unsigned int &pSourcePort,
                      QObject *parent) :
    QObject(parent),
    mTcpSocket(new QTcpSocket(this)),
    mSourceAddress(pSourceAddress),
    mSourcePort(pSourcePort),
    mData(new QVector<float>)

    for( unsigned int i = 0; i < mDataSize; i++)
        mData->append(.0);


DataReceiver::~DataReceiver()
    mTcpSocket->disconnectFromHost();
    mTcpSocket->waitForDisconnected();
    delete mTcpSocket;

    delete mData;


// Network Management
bool DataReceiver::connectToHost(void)
    connect(mTcpSocket, SIGNAL(connected()), this, SLOT(onConnect()));
    connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
    connect(mTcpSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
    connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(onDataReceived()));

    qDebug() << "connecting...";

    //emit mTcpSocket->readyRead(); // For testing. We correctly trigger the onDataReceived slot

    mTcpSocket->open(QAbstractSocket::ReadWrite);
    mTcpSocket->connectToHost(getSourceAddress(), getSourcePort());

    if(!mTcpSocket->waitForConnected(1000))
    
        qDebug() << "Error: " << mTcpSocket->errorString();
        return false;
    
    mTcpSocket->write("Hello ?"); // Test
    return true;


// Getters
QVector<float> *DataReceiver::getData(void) const
    return mData;


QTcpSocket *DataReceiver::getTcpSocket(void) const
    return mTcpSocket;


QString DataReceiver::getSourceAddress(void) const
    return mSourceAddress;


unsigned int DataReceiver::getSourcePort(void) const
    return mSourcePort;


// Setters
void DataReceiver::setData(const QVector<float> *pData)
    // Not yet implemented
    Q_UNUSED(pData);


void DataReceiver::setSourceAddress(const QString &pSourceAddress)
    mSourceAddress = pSourceAddress;


void DataReceiver::setSourcePort(const unsigned int &pSourcePort)
    mSourcePort = pSourcePort;


// Public Slots
void DataReceiver::onConnect()
    qDebug() << "connected...";


void DataReceiver::onDisconnect()
    qDebug() << "disconnected...";


void DataReceiver::onBytesWritten(qint64 bytes)
    qDebug() << bytes << " bytes written...";


// Private Slots
void DataReceiver::onDataReceived()
    // Not yet implemented, code is for testing
    qDebug() << "onDataReceived called !";

    while(mTcpSocket->bytesAvailable())
        qInfo() << mTcpSocket->read(mTcpSocket->bytesAvailable());
        qDebug() << mTcpSocket->readAll();
    


// Private Methods
void DataReceiver::decodeData(const QByteArray &pMessage)
    // Not yet implemented
    Q_UNUSED(pMessage);

此处的 mData/mDataSize 供将来使用,因此此处应忽略。

发件人

为了发送数据,我尝试使用 netcat

cat testfile.txt | nc 127.0.0.1 51470

我还创建了一个 DataSender 类,其结构与 DataReceiver 类相同。 根据 Wireshark 的说法,这两种方法似乎都是通过 TCP 写入数据。

DataSender 类

datasender.h

class DataSender : QObject

    Q_OBJECT

public:
    // Con/Destructors
    explicit DataSender(QObject *parent = nullptr);
    ~DataSender();

    // Network Management
    bool connectToHost(void);
    void sendData(void) const;

    // Getters
    QString getDestinationAddress(void) const;
    unsigned int getDestinationPort(void) const;

    // Setters
    void setDestinationAddress(const QString &pDestinationAddress);
    void setDestinationPort(const unsigned int &pDestinationPort);

signals:

public slots:
    void onConnect();
    void onDisconnect();
    void onBytesWritten(qint64 bytes);
    void onDataReceived();

private:
    QTcpSocket *mTcpSocket;
    QString mDestinationAddress;
    unsigned int mDestinationPort;
;

datasender.cpp

DataSender::DataSender(QObject *parent) :
    QObject(parent),
    mTcpSocket(new QTcpSocket(this)),
    mDestinationAddress("127.0.0.1"),
    mDestinationPort(50911)




DataSender::~DataSender()
    mTcpSocket->disconnectFromHost();
    mTcpSocket->waitForDisconnected();
    delete mTcpSocket;


// Network Management
bool DataSender::connectToHost(void)
    connect(mTcpSocket, SIGNAL(connected()), this, SLOT(onConnect()));
    connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
    connect(mTcpSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
    connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(onDataReceived()));

    qDebug() << "connecting...";

    mTcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption, true);

    mTcpSocket->connectToHost(getDestinationAddress(), getDestinationPort());

    if(!mTcpSocket->waitForConnected(1000))
    
        qDebug() << "Error: " << mTcpSocket->errorString();
        return false;
    
    return true;


void DataSender::sendData(void) const
    QByteArray lData("Hello, this is DataSender ! Do you copy ? I repeat, do you copy ?");

    QByteArray lTemp;
    QDataStream lData2(&lTemp, QIODevice::ReadWrite);
    lData2 << lData.size();

    if(mTcpSocket->state() == QAbstractSocket::ConnectedState)
    
        mTcpSocket->write(lTemp); //write size of data
        mTcpSocket->write(lData); //write the data itself
        mTcpSocket->waitForBytesWritten();
    


// Getters
QString DataSender::getDestinationAddress(void) const
    return mDestinationAddress;


unsigned int DataSender::getDestinationPort(void) const
    return mDestinationPort;


// Setters
void DataSender::setDestinationAddress(const QString &pDestinationAddress)
    mDestinationAddress = pDestinationAddress;


void DataSender::setDestinationPort(const unsigned int &pDestinationPort)
    mDestinationPort = pDestinationPort;


// Public Slots
void DataSender::onConnect()
    qDebug() << "connected...";


void DataSender::onDisconnect()
    qDebug() << "disconnected...";


void DataSender::onBytesWritten(qint64 bytes)
    qDebug() << bytes << " bytes written...";


void DataSender::onDataReceived()
    // Not yet implemented, code is for testing
    qDebug() << "onDataReceived called !";

    //while(mTcpSocket->bytesAvailable())
        //qInfo() << mTcpSocket->read(mTcpSocket->bytesAvailable());
        //qDebug() << mTcpSocket->readAll();
    //

客户端主要

// Main routine ---------------------------------
int main(int argc, char **argv)

    // Initializing application.
    QApplication lApplication(argc, argv);

    CLIENT::DataReceiver dataReceiver;
    dataReceiver.connectToHost();

    return lApplication.exec();

服务器端主

// Main routine ---------------------------------
int main(int argc, char **argv)
    QApplication lApplication(argc, argv);

    SERVER::DataSender lDataSender;
    lDataSender.connectToHost();
    lDataSender.sendData();

    return lApplication.exec();

行为

基本上,当我在 main 中运行 DataReceiver 类时,我会得到以下行为:

connecting...
connected...
7 bytes written...       # This is the write("Hello ?") I inserted just for testing

# "connected..." may occur after "7 bytes written...", 
# I don't remember, I am not in front of my computer right now. 

结论

我相信我只是忘记了一些重要的事情,或者有些事情我不知道。这是一个个人项目,所以欢迎一些外部见解!

非常感谢!

丁香

【问题讨论】:

您的代码中是否运行了事件循环?发送数据是一回事,但您没有包括发送给您的服务器部分。你的客户端类在我看来没问题。 有了这段代码,即使我有问题// QTcpSocket 绑定到QHostAdress 而不是字符串? 嗨@user3606329。认为 qApplication 是“while(1)”例程,但也许不是。我需要检查带有 while(true) 循环的类的行为,看看它是否改变了任何东西。服务器/发送器部分由像这样的 DataSender 类或 netcat 命令播放。嗨 Mohammad,QTcpSocket 有几个构造函数,您指的是其中之一。其中有:QTcpSocket(const QString& Address, const int& port) QTcpSocket(const QHostAddress& Address)。顺便说一句,QHostAddress 的一个构造函数接受 QString 和 int 作为参数。 除了这里的问题之外,是否有特定原因使用 TCP over 127.0.0.1,而不是 QLocalSocket 嗨@TheDarkKnight。有:我不知道 QLocalSocket 存在。并且在不久的将来(不是那么快),另一个 IP 地址将取代“localhost”。 【参考方案1】:

QTcpSocket 可以与另一个 QTcpSocket 通信,但为​​了实现这一点,必须使用 client-server model 建立初始连接。

QTcpSocket 无法侦听传入连接。相反,可以使用QTcpServer(或QLocalServer,如果使用QLocalSocket)。

QTcpSocket 在用于传入连接的端口上设置为listen,当建立连接时,将发出信号通知newConnection。调用nextPendingConnection 为服务器端返回QTcpSocket,允许它通过传入连接与客户端通信。

【讨论】:

非常感谢您的澄清!我实现了一个 QTcpServer,它确实有效!我使用与以前相同的方法对其进行了测试:netcat 和我编写的DataSender 类。【参考方案2】:

所以这是 OP,这是我实施的解决方案。我要感谢@TheDarkKnight 和@G.M。为了他们的澄清。

解决方案

我的DataReceiver 类没有使用QTcpSocket,而是使用QTcpSocket 的组合AND QTcpServer。基本上,QTcpServer 监听新连接并在建立连接时设置QTcpSocket

然后,该类简单地将QTcpSocket 信号readyRead() 连接到个人插槽。这是该类的实现:

DataReceiver 类

datareceiver.h

class DataReceiver : QObject

    Q_OBJECT

public:
    // Con/Destructors
    explicit DataReceiver(QObject *parent = nullptr);
    explicit DataReceiver(const QString &pSourceAddress,
                          const unsigned int &pSourcePort,
                          QObject *parent = nullptr);
    ~DataReceiver();

    // Getters
    QVector<float> *getData(void) const;
    QTcpServer *getTcpServer(void) const;
    QString getSourceAddress(void) const;
    unsigned int getSourcePort(void) const;

    // Setters
    void setData(const QVector<float> *pData);
    void setSourceAddress(const QString &pSourceAddress);
    void setSourcePort(const unsigned int &pSourcePort);

signals:

public slots:
    void onConnect();
    void onDisconnect();
    void onBytesWritten(qint64 bytes);
    void onDataReceived();
    void onNewConnection();

private:
    void decodeData(const QByteArray &pMessage);

    QTcpServer *mTcpServer;
    QTcpSocket *mTcpSocket;
    QString mSourceAddress;
    unsigned int mSourcePort;

    const unsigned int mDataSize = 30;
    QVector<float> *mData;
;

datareceiver.cpp

// Con/Destructors
DataReceiver::DataReceiver(QObject *parent) :
    QObject(parent),
    mTcpServer(new QTcpServer(this)),
    mSourceAddress("127.0.0.1"),
    mSourcePort(51470),
    mData(new QVector<float>)

    for( unsigned int i = 0; i < mDataSize; i++)
        mData->append(.0);

    connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));

    if(!mTcpServer->listen(QHostAddress(getSourceAddress()), getSourcePort()))
        qDebug() << "<DataReceiver> Server could not start. ";
    else
        qDebug() << "<DataReceiver> Server started !";


DataReceiver::DataReceiver(const QString &pSourceAddress,
                      const unsigned int &pSourcePort,
                      QObject *parent) :
    QObject(parent),
    mTcpServer(new QTcpServer(this)),
    mSourceAddress(pSourceAddress),
    mSourcePort(pSourcePort),
    mData(new QVector<float>)

    for( unsigned int i = 0; i < mDataSize; i++)
        mData->append(.0);

    connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));

    if(!mTcpServer->listen(QHostAddress(getSourceAddress())), getSourcePort())
        qDebug() << "<DataReceiver> Server could not start. ";
    else
        qDebug() << "<DataReceiver> Server started !";



DataReceiver::~DataReceiver()
    delete mTcpServer;

    delete mData;


// Getters
QVector<float> *DataReceiver::getData(void) const
    return mData;


QTcpServer *DataReceiver::getTcpServer(void) const
    return mTcpServer;


QString DataReceiver::getSourceAddress(void) const
    return mSourceAddress;


unsigned int DataReceiver::getSourcePort(void) const
    return mSourcePort;


// Setters
void DataReceiver::setData(const QVector<float> *pData)
    // Not yet implemented
    Q_UNUSED(pData);


void DataReceiver::setSourceAddress(const QString &pSourceAddress)
    mSourceAddress = pSourceAddress;


void DataReceiver::setSourcePort(const unsigned int &pSourcePort)
    mSourcePort = pSourcePort;


// Public Slots
void DataReceiver::onConnect()
    qDebug() << "QTcpSocket connected...";


void DataReceiver::onDisconnect()
    qDebug() << "QTcpSocket disconnected...";
    disconnect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(onDataReceived()));
    disconnect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));


void DataReceiver::onBytesWritten(qint64 bytes)
    qDebug() << bytes << " bytes written to QTcpSocket...";


void DataReceiver::onDataReceived()
    // Not yet implemented, code is for testing
    qDebug() << "onDataReceived called !";

    while(mTcpSocket->bytesAvailable())
        qInfo() << mTcpSocket->read(mTcpSocket->bytesAvailable());
        qDebug() << mTcpSocket->readAll();
    


void DataReceiver::onNewConnection()
    qDebug() << "onNewConnection called !";
    mTcpSocket = mTcpServer->nextPendingConnection();

    connect(mTcpSocket, SIGNAL(readyRead()),    this, SLOT(onDataReceived()));
    connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));


// Private Methods
void DataReceiver::decodeData(const QByteArray &pMessage)
    // Not yet implemented
    Q_UNUSED(pMessage);

【讨论】:

以上是关于没有 QTcpSocket 接收的主要内容,如果未能解决你的问题,请参考以下文章

qtcpsocket只能接收8KB字节的数据,该怎么解决

QTcpSocket类中的ReadyRead()信号没有被触发

为啥 QTcpSocket 接收到错误的数据?

QTcpSocket:解码接收到的数据

QTcpSocket 从服务器接收数据

QTcpSocket的连续发送数据和连续接收数据