2017-09-18 19 views
0

때문에 자신의 래퍼를 구현하려고하는데, 그 이유는 uncomfortable to use이기 때문입니다. 사용할 수는 있지만 어쨌든 QDataStream 조작에 액세스하려면 중간 버퍼를 구현해야합니다. 추가 년 :서브 클래 싱 QIODevice : 래퍼 QUdpSocket에 대한

나는 sublass QIODevice,
헤더 (비트 간체) :

class BerUdp : public QIODevice 
{ 
    Q_OBJECT 

    void startup(); 

public: 
    void setHostToWrite(const QHostAddress &address, quint16 port); 
    void setPortToRead(quint16 port); 

    qint64 bytesAvailable() const; 

protected: // Reimplement: 
    qint64 readData(char *data, qint64 maxSize); 
    qint64 writeData(const char *data, qint64 maxSize); 

private: 
    QUdpSocket* dev_write; // udp socket to write 
    QUdpSocket* dev_read; // udp socket to read 

    QBuffer  m_buffer; // buffer to store received datagrams 
}; 

.cpp 파일 : 쿼트 documuntation에서

void BerUdp::startup() 
{  
    m_buffer.open(QIODevice::ReadWrite);  
    open(QIODevice::ReadWrite); 
} 

void BerUdp::setHostToWrite(const QHostAddress &address, quint16 port) 
{ 
    dev_write->connectToHost(address, port); 
    dev_write->waitForConnected(); 
} 

void BerUdp::setPortToRead(quint16 port) 
{ 
    dev_read->bind(port); 
    dev_read->open(QIODevice::ReadOnly); 

    bool ok = connect(dev_read, &QIODevice::readyRead, 
     this, &BerUdp::onReceive); 
}  

// Read new received data to my internal buffer 
void BerUdp::onReceive() 
{ 
    bool av = dev_read->hasPendingDatagrams(); 
    if (av) 
    { 
     int dSize = dev_read->pendingDatagramSize(); 
     QByteArray dtg(dSize, 0); 
     dev_read->readDatagram(dtg.data(), dtg.size());  

     // write new data to the end 
     int buf_read_pos = m_buffer.pos(); 
     m_buffer.seek(m_buffer.size()); 
     m_buffer.write(dtg); 
     m_buffer.seek(buf_read_pos); 
    } 
} 

QIODevice::readData()

..이 함수를 다시 구현할 때이 함수 이 반환하기 전에 필요한 모든 데이터를 읽는 것이 중요합니다. QDataStream이 클래스에서 작동 할 수 있으려면 순서가 필요합니다. QDataStream 는 ... 문제가 있다면하지 재시도 읽고 않습니다 그러므로 모든 요청 된 정보가 읽은 가정 :

// Main read data function. There are only 4 bytes required, but maxSize == 0x4000 here: 
qint64 BerUdp::readData(char *data, qint64 maxSize) 
{  
    int n = m_buffer.read(data, maxSize); 

    // clear the data which has already read: 
    QByteArray& ba = m_buffer.buffer(); 
    ba.remove(0, n); // m_buffer.size() == 0 after this 
    m_buffer.seek(0); 

    return n; 
} 

문제는 첫 번째 읽기 후에 나는 그러므로 내를 빈 버퍼를 가지고 있고,이다 bytesAvailable() 방법은 0 반환

:

qint64 BerUdp::bytesAvailable() const 
{  
    qint64 my_size = m_buffer.size(); 
    qint64 builtin_size = QIODevice::bytesAvailable(); 

    return (my_size + builtin_size); // == 0 after 1st read 
} 

그래서 내가 사용할 수 있습니다 얼마나 많은 바이트를 찾을 수 없습니다 예를 들어 클래스를 사용할 때

QUdpSocket의 포장지를 올바르게 쓰려면 어떻게해야합니까?
로직을 별도의 QIODevice 유도 클래스로 이동하기 전까지는 중간 버퍼를 사용하는 것이 효과적이었습니다.

답변

0

Qt 소스로 디버깅하는 과정에서 isSequential() 속성을 true으로 설정해야한다는 것을 알게되었습니다. 이제는 수업이 올바로 작동합니다.

bool BerUdp::isSequential() const 
{ 
    return true; 
} 

전체 클래스 :

BerUdp.h

#pragma once 

#include <QIODevice> 
#include <QBuffer> 

class QUdpSocket; 
class QHostAddress; 

class BerUdp : public QIODevice 
{ 
    Q_OBJECT 

public: 
    BerUdp(QObject *parent = 0); 
    void startup();  

    void setHostToWrite(const QHostAddress &address, quint16 port); 
    void setPortToRead(quint16 port); 

    bool flush(); 
    qint64 bytesAvailable() const; 
    bool waitForReadyRead(int msecs); 
    bool isSequential() const; 

protected: // Main necessary reimplement 
    qint64 readData(char *data, qint64 maxSize); 
    qint64 writeData(const char *data, qint64 maxSize); 

private slots: 
    void onReceive(); 

private: 
    void read_udp_datagram(); 
    void write_new_data_to_buffer(QByteArray dtg); 

private: 
    QUdpSocket* dev_write; // One udp socket to write 
    QUdpSocket* dev_read; // Another udp socket to read 

    // intermediate buffer to store received datagrams 
    // and to provide access to read- and QDataStream- operations 
    QBuffer  m_buffer; 
}; 

BerUdp.cpp

#include "BerUdp.h" 
#include <QUdpSocket> 

BerUdp::BerUdp(QObject *parent) 
    : QIODevice(parent) 
{ 
    startup(); 
} 

// Initialization 
void BerUdp::startup() 
{ 
    dev_write = new QUdpSocket(this); 
    dev_read = new QUdpSocket(this); 

    m_buffer.open(QIODevice::ReadWrite); 
    open(QIODevice::ReadWrite); 
} 

// Set a virtual connection to "host" 
void BerUdp::setHostToWrite(const QHostAddress &address, quint16 port) 
{ 
    dev_write->connectToHost(address, port); 
    dev_write->waitForConnected(); 
} 

// Bind a port for receive datagrams 
void BerUdp::setPortToRead(quint16 port) 
{ 
    dev_read->bind(port); 
    dev_read->open(QIODevice::ReadOnly); 

    connect(dev_read, &QIODevice::readyRead, 
     this, &QIODevice::readyRead); 
    connect(dev_read, &QIODevice::readyRead, 
     this, &BerUdp::onReceive); 
} 

// Flush written data 
bool BerUdp::flush() 
{ 
    return dev_write->flush(); 
} 

// Returns the number of bytes that are available for reading. 
// Subclasses that reimplement this function must call 
// the base implementation in order to include the size of the buffer of QIODevice. 
qint64 BerUdp::bytesAvailable() const 
{ 
    qint64 my_size = m_buffer.size(); 
    qint64 builtin_size = QIODevice::bytesAvailable(); 

    return (my_size + builtin_size); 
} 

bool BerUdp::waitForReadyRead(int msecs) 
{ 
    return dev_read->waitForReadyRead(msecs); 
} 

// Socket device should give sequential access 
bool BerUdp::isSequential() const 
{ 
    return true; 
} 

// This function is called by QIODevice. 
// It is main function for provide access to read data from QIODevice-derived class. 
// (Should be reimplemented when creating a subclass of QIODevice). 
qint64 BerUdp::readData(char *data, qint64 maxSize) 
{ 
    int n = m_buffer.read(data, maxSize); 

    // clear the data which has already been read 
    QByteArray& ba = m_buffer.buffer(); 
    ba.remove(0, n); 
    m_buffer.seek(0); 

    return n; 
} 

// This function is called by QIODevice. 
// It is main function for provide access to write data to QIODevice-derived class. 
// (Should be reimplemented when creating a subclass of QIODevice). 
qint64 BerUdp::writeData(const char *data, qint64 maxSize) 
{ 
    return dev_write->write(data, maxSize); 
} 

// Read new available datagram 
void BerUdp::read_udp_datagram() 
{ 
    int dSize = dev_read->pendingDatagramSize(); 
    QByteArray dtg(dSize, 0); 
    dev_read->readDatagram(dtg.data(), dtg.size()); 

    write_new_data_to_buffer(dtg); 
} 

// Write received data to the end of internal intermediate buffer 
void BerUdp::write_new_data_to_buffer(QByteArray dtg) 
{ 
    int buf_read_pos = m_buffer.pos(); 
    m_buffer.seek(m_buffer.size()); 
    m_buffer.write(dtg); 
    m_buffer.seek(buf_read_pos); 
} 

// Is called on readyRead signal 
void BerUdp::onReceive() 
{ 
    bool available = dev_read->hasPendingDatagrams(); 
    if (available) 
    { 
     read_udp_datagram(); 
    } 
}