没有接收 w/ QTcpSocket

No reception w/ QTcpSocket

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

问题

所以:我有一个名为 DataReceiver 的接收 class。基本上,我只想从本地主机 (127.0.0.1) 网络上的 TCP 套接字接收数据。似乎我可以使用此套接字进行写入(我使用 Wireshark 软件进行了检查),但程序似乎没有收到任何东西。

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

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

数据接收器class

此 class 的代码如下:

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 class,其结构与 DataReceiver class 相同。 根据 Wireshark 的说法,这两种方法似乎都是通过 TCP 写入数据。

数据发送器class

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

行为

基本上,当我 运行 主 DataReceiver class 时,我得到以下行为:

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 can communicate with another QTcpSocket, but in order for this to happen, an initial connection must be made, utilising a client-server model.

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

服务器端的QTcpSocket设置为listen on a port for incoming connections and when a connection is made, will emit a signal to notify of the newConnection. Calling nextPendingConnectionreturnsQTcpSocket,允许它从传入连接与客户端通信。

这就是 OP,这是我实现的解决方案。我要感谢@TheDarkKnight & @G.M。为了他们的澄清。

解决方案

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

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

数据接收器class

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