readyRead()在Qt中如何工作?

时间:2014-10-28 15:56:45

标签: c++ qt qtcore qtserialport qiodevice

这是我在这个网站上的第一个问题!

我在从COM端口读取数据时遇到一些麻烦,我从另一个COM端口发送完整的消息,当我用Qt接收它时,它总是被多个子消息切断。

void SerialPortReader::init()
{
    connect(m_serialPort, SIGNAL(readyRead()), this, SLOT(readData()));
}   

void SerialPortReader::readData()
{
//    m_serialPort->waitForReadyRead(200);
    QByteArray byteArray = m_serialPort->readAll();
    qDebug() << byteArray;

    if(byteArray.startsWith(SOF) && byteArray.endsWith(EOF_LS)
        && byteArray.size() >= MIN_SIZE_DATA) {
    decodeData(byteArray.constData());
    } else {
        qDebug() << "LIB SWCom : Unvalid trame !";
    }
}

发送的消息长度为25或27字节,如果我使用Putty或Hyperterminal来阅读它们,我没有遇到麻烦。 另外如果我使用2个模拟串口COM进行通信,我没有这个问题...... 它只发生在Qt读取系统和2个物理COM端口......

我认为在准确发出readyRead信号时我无法得到......

我很困惑,请提前感谢您的帮助!

3 个答案:

答案 0 :(得分:9)

documentation实际上非常清楚:

  

void QIODevice :: readyRead()[signal]

     

每当有新数据可供设备读取时,此信号就会发出一次。只有在新数据可用时才会再次发出,例如网络数据的新有效负载已经到达您的网络套接字,或者新的数据块已经附加到您的设备上。

     

readyRead()不是递归发出的;如果你重新进入事件循环或在连接到readyRead()信号的槽内调用waitForReadyRead(),则不会重新发送信号(尽管waitForReadyRead()仍然可以返回true)。

     

对于实现从QIODevice派生的类的开发人员的注意事项:当新数据到达时,您应该始终发出readyRead()(仅仅因为仍然要在缓冲区中读取数据而不发出它)。不要在其他条件下发出readyRead()。

这意味着无法确保有多少数据可供阅读,只有部分数据可用。

如果您希望读取的数据多于一次性输入的数据,您可能会选择超时值和/或readyRead。这取决于你想要达到的目标。

请参阅我之前为此操作编写的command line async reader example

#include "serialportreader.h"

#include <QCoreApplication>

QT_USE_NAMESPACE

SerialPortReader::SerialPortReader(QSerialPort *serialPort, QObject *parent)
    : QObject(parent)
    , m_serialPort(serialPort)
    , m_standardOutput(stdout)
{
    connect(m_serialPort, SIGNAL(readyRead()), SLOT(handleReadyRead()));
    connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), SLOT(handleError(QSerialPort::SerialPortError)));
    connect(&m_timer, SIGNAL(timeout()), SLOT(handleTimeout()));

    m_timer.start(5000);
}

SerialPortReader::~SerialPortReader()
{
}

void SerialPortReader::handleReadyRead()
{
    m_readData.append(m_serialPort->readAll());

    if (!m_timer.isActive())
        m_timer.start(5000);
}

void SerialPortReader::handleTimeout()
{
    if (m_readData.isEmpty()) {
        m_standardOutput << QObject::tr("No data was currently available for reading from port %1").arg(m_serialPort->portName()) << endl;
    } else {
        m_standardOutput << QObject::tr("Data successfully received from port %1").arg(m_serialPort->portName()) << endl;
        m_standardOutput << m_readData << endl;
    }

    QCoreApplication::quit();
}

void SerialPortReader::handleError(QSerialPort::SerialPortError serialPortError)
{
    if (serialPortError == QSerialPort::ReadError) {
        m_standardOutput << QObject::tr("An I/O error occurred while reading the data from port %1, error: %2").arg(m_serialPort->portName()).arg(m_serialPort->errorString()) << endl;
        QCoreApplication::exit(1);
    }
}

在这种情况下,命令行阅读器示例将获取一次性传递的任何数据,但不保证长度或任何内容。

此外,请注意,您所评论的同步api与您询问的异步API一起没有多大意义。我在这里指的是m_serialPort->waitForReadyRead(200);

答案 1 :(得分:1)

只要有待处理的数据并且之前执行的readyRead已经完成,就会发出readyRead信号。

文档说:

  

每次有新数据时,都会发出一次该信号   从设备上读取。只有新数据才会再次发出   可用,例如当新的网络数据有效载荷到达时   在您的网络套接字上,或附加了新的数据块   到你的设备。

     

readyRead()不是递归发出的;如果你重新进入事件循环   或者在连接到readyRead()的插槽中调用waitForReadyRead()   信号,信号不会被重新发送(虽然waitForReadyRead()   可能仍然会返回真实。)

如果这会导致您的情况出现任何问题,您可以使用while循环检查bytesAvailable()。

答案 2 :(得分:1)

在这里使用Thread概念,使用你可以实现这一点的线程...在一个单独的线程中运行你的portread然后它将正常工作,否则消息将被切断。 其他方法你可以使用Qprocess并使用QProcess打开一个新终端并将端口号和连接细节发送到该终端并从Qt运行它然后你也可以存档这个

我的意思是我们可以在这里使用therad和socket通信看看这段代码

    QTcpSocket *SocketTest::getSocket() {
        return socket;
    }

    void SocketTest::Connect()

    {

        socket = new QTcpSocket(this);
        socket->connectToHost("127.0.0.1",22);
        if(socket->waitForConnected(3000))
        {

            qDebug()<<"connect";
            socket->waitForBytesWritten(3000);
            socket->waitForReadyRead(1000);
         Settings::sockdata=socket->readAll();
           qDebug()<<Settingssock::sockets;
           socket->close();

        }
        else
        {
             qDebug()<<" not connect";

        }
    }


............ call socket 

 SocketTest sock;
    sock.Connect();
    QTcpSocket * socket = sock.getSocket();
       QObject *ob= new QThread;
       mythread thread1(socket);
    thread = new mythread(socket);
    thread.run();
    thread->start();
   thread->wait();

这是一个简单的telnet连接示例,同样你可以指定你想连接哪个端口并连接到哪个ip