C++ readyRead() 在 Qt 中是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26612852/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how does readyRead() work in Qt?
提问by palador
It's my first question on this website !
这是我在这个网站上的第一个问题!
I have some trouble reading datas from a COM port, I send a complete message from another COM port, and when I receive it with Qt, it's always cut in multiple submessages.
我在从一个 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 !";
}
}
the messages sent are 25 or 27 Bytes long, if I use Putty or an Hyperterminal to read them, I have no trouble. Also if I use 2 emulated serial port COM to communicate, I don't have this problem... It only occurs with Qt reading system AND with 2 physical COM port...
发送的消息长度为 25 或 27 字节,如果我使用 Putty 或超级终端读取它们,我没有问题。另外,如果我使用 2 个仿真串口 COM 进行通信,我就没有这个问题......它只发生在 Qt 读取系统和 2 个物理 COM 端口......
I think I don't get when the readyRead signal is emitted exactly...
我想我不明白什么时候 readyRead 信号被准确地发出......
I'm very confuse, Thank you in advance for your help !
我很困惑,在此先感谢您的帮助!
回答by lpapp
The documentationis actually quite clear about it:
该文件实际上是它很清楚:
void QIODevice::readyRead() [signal]
This signal is emitted once every time new data is available for reading from the device. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).
Note for developers implementing classes derived from QIODevice: you should always emit readyRead() when new data has arrived (do not emit it only because there's data still to be read in your buffers). Do not emit readyRead() in other conditions.
void QIODevice::readyRead() [信号]
每次可从设备读取新数据时,都会发出一次该信号。它只会在新数据可用时再次发出,例如当网络数据的新有效负载到达您的网络套接字时,或者当新的数据块已附加到您的设备时。
readyRead() 不会递归发出;如果您重新进入事件循环或在连接到 readyRead() 信号的插槽内调用 waitForReadyRead(),则不会重新发送该信号(尽管 waitForReadyRead() 可能仍会返回 true)。
实现从 QIODevice 派生的类的开发人员的注意事项:当新数据到达时,您应该始终发出 readyRead()(不要仅仅因为缓冲区中仍有数据要读取而发出它)。不要在其他条件下发出 readyRead()。
This means that it is not really guaranteed how much data will be available for reading, just that some will be available.
这意味着不能真正保证有多少数据可供读取,只是有些数据是可用的。
If you wish to read more data than it is coming in one go, you may be opt for a timeout value and/or readyRead. It depends on what you are trying to achieve.
如果您希望读取的数据多于一次性读取的数据,您可以选择超时值和/或 readyRead。这取决于您要实现的目标。
See the command line async reader examplethat I wrote a while ago for this operation, too:
请参阅我前段时间为此操作编写的命令行异步阅读器示例:
#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);
}
}
In this case, the command line reader example will get any data that was passed in one shot, but it does not guarantee the length or anything.
在这种情况下,命令行阅读器示例将获取一次性传递的任何数据,但不保证长度或任何内容。
Also, please note that the sync api that is behind your comments does not make much sense along with the async API that you are asking about. I am referring to m_serialPort->waitForReadyRead(200);
in here.
另外,请注意,您评论后面的同步 API 与您所询问的异步 API 没有多大意义。我m_serialPort->waitForReadyRead(200);
在这里指的是。
回答by Robert
The readyRead-signal is emitted whenever there is pending data AND the previous execution of readyRead has finished.
只要有待处理的数据并且前一次 readyRead 执行完成,就会发出 readyRead 信号。
Documentation says:
文档说:
This signal is emitted once every time new data is available for reading from the device. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).
每次可从设备读取新数据时,都会发出一次该信号。它只会在新数据可用时再次发出,例如当网络数据的新有效负载到达您的网络套接字时,或者当新的数据块已附加到您的设备时。
readyRead() 不会递归发出;如果您重新进入事件循环或在连接到 readyRead() 信号的插槽内调用 waitForReadyRead(),则不会重新发送该信号(尽管 waitForReadyRead() 可能仍会返回 true)。
If this should lead to any problems in your case, you could use a while-loop where you check for bytesAvailable().
如果这会导致您的情况出现任何问题,您可以使用 while 循环来检查 bytesAvailable()。
回答by Arunprasanth K V
Use Thread concept here , using threads you can achieve this... run your portread in a seperate thread then it will be works fine, other wise the message will be cut. other method u can use Qprocess and open a new terminal using QProcess and send the port number and connectivity details to that terminal and run it from Qt then also u can archive this
在这里使用线程概念,使用线程可以实现这一点...在单独的线程中运行您的 portread 然后它会工作正常,否则消息将被切断。其他方法您可以使用 Qprocess 并使用 QProcess 打开一个新终端并将端口号和连接详细信息发送到该终端并从 Qt 运行它然后您也可以将其存档
i mean we can use therad and socket communication here look at this code
我的意思是我们可以在这里使用 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();
this is a simple example of telnet connection, likewise u can specify which port you want connect and connected to which ip
这是一个简单的 telnet 连接示例,同样,您可以指定要连接的端口并连接到哪个 ip