2016-08-26 32 views
0

我想發送和接收使用QTCPSocket的結構。如何通過QTcpSocket接收結構?

該系統確實有一箇中央套接字服務器和大量的Qt客戶端應用程序。 每個客戶端都會發送一個由中心套接字服務器廣播給其餘結構的結構。

Connector延伸QTcpSocket

這是我的用於連接

void Connector::Open(QString address, int port) // It works! 
{ 
    connectToHost(address, port); 
    this->onWaiting(); 

    connect(this, SIGNAL(connected()), this, SLOT(connected())); 
    connect(this, SIGNAL(disconnected()), this, SLOT(disconnected())); 
    connect(this, SIGNAL(readyRead()), this, SLOT(readyRead())); 
    connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64))); 
} 

方法這是我的用於發送數據

void Connector::SendData(const void* data,qint64 len) // It works! 
{ 
    writeData((char*)data,len); 
    waitForBytesWritten(); 
} 

這是用於接收

void Connector::readyRead() // Don't work 
{ 
    Information n; //My struct 
    memcpy(&n, data.data(), data.size()); 
    onInformationReceived(n); 
} 
方法

但收到的信息始終無效。那是對的嗎?

+0

你送什麼樣的數據? – purplepsycho

回答

0

有一些問題:

  1. readyRead()槽可以與任何數量可供讀取的字節被調用。您唯一的保證是它超過零字節,儘管在實踐中沒有理由指望它。你必須檢查bytesAvailable。它可以是一個字節。它可以是一兆字節。

    參見例如this answerthat answer爲敘述,that one爲代碼。

    在最低限度,你需要:

    ​​
  2. 發送struct爲通過線路將無法正常工作不透明的二進制文件。沒有保證接收端會以相同的方式佈局結構。你甚至不知道數據的二進制格式是什麼,除非你參考你的編譯器ABI文檔。

    參見例如this answer如何正確地做到這一點。

    在最低限度,你需要實現QDataStream流媒體運營商Information,然後用它在連接的兩端:

    QDataStream & operator<<(QDataStream &, const Information &); 
    QDataStream & operator>>(QDataStream &, Information &); 
    
    void Connector::send(const Information & info) { 
        auto dev = this; // We're a QIODevice :(
        QDataStream stream{dev}; 
        stream << info; 
        dev.waitForBytesWritten(); // this is superbly bad! 
    } 
    
    void Connector::readyRead() { 
        auto dev = this; // We're a QIODevice :(
        QDataStream stream{dev}; 
        stream.startTransaction(); 
        Information info; 
        dev >> info; 
        if (! stream.commitTransaction()) return; 
        onInformationReceived(info); 
    } 
    
  3. 你不應該延長QTcpSocket。你的課程應該是一個QObject,其價值爲QTcpSocket

  4. 你不應該阻止。

因此,固定的Connector類可能如下所示。再次,this answer描述瞭如何正確使用QDataStream來說明與將來的代碼更新的兼容性。但是請參閱this answer瞭解如何利用Qt 5.7的QDataStream中的讀取事務。

class Connector : public QObject { 
    Q_OBJECT 
    QTcpDevice m_dev; 
    QDataStream m_str{&m_dev}; 
    void onReadyRead() { 
    m_str.startTransaction(); 
    Information info; 
    m_str >> info; 
    if (! stream.commitTransaction()) return; 
    onInformationReceived(info); 
    } 
    void onBytesWritten() { 
    if (m_dev.bytesToWrite() == 0) 
     emit allDataSent(); 
    } 
    void onInformationReceived(const Information &); 
public: 
    Connector(const QString & address, int port, QObject * parent = nullptr) : 
    QObject{parent} 
    { 
    connect(&m_dev, &QAbstractSocket::connected, this, &Connector::connected); 
    connect(&m_dev, &QAbstractSocket::disconnected, this, &Connector::disconnected); 
    connect(&m_dev, &QIODevice::readyRead, this, onReadyRead); 
    connect(&m_dev, &QIODevice::bytesWritten, this, onBytesWritten); 
    m_dev.connect(address, port); 
    } 
    void send(const Information & info) { 
    m_str << info; 
    } 
    Q_SIGNAL void connected(); 
    Q_SIGNAL void disconnected(); 
    Q_SIGNAL void allDataSent(); 
}