QT5.14,Server-Client应用,Server为树莓派;Client为Android设备,代码用QT编写封装为so
Android上点击按钮,调用so发送数据,Server能正常接收数据。
Server原路(获取到ip和port)发送给Client响应数据,然而Client就是不触发readyRead信号。
解决:
在通过udp发送数据的地方,调用waitForReadyRead,问题解决。
void SocketTester::sendMessage(QString msg)
{
QNetworkDatagram datagram;
datagram.setData(msg.toLatin1());
datagram.setDestination(QHostAddress(mIP), mPort);
mUDPSocket->writeDatagram(datagram);
mUDPSocket->waitForReadyRead();
}
后续测试时发现,连续快速发送数据时readyRead信号不再触发,使用mUDPSocket->bytesAvailable()不为空,说明Socket接收缓冲区实际有数据,但为什么没有触发ReadyRead信号呢?
发送过快,然而程序没有及时从缓冲区里取数据就会造成缓冲滞留数据的问题,也许Qt发送ReadyRead信号的判断方法是当缓冲区从空状态到有数据状态,如果之前的数据没有及时取走,以后不会触发信号。
后续的解决方法:
开一个子线程,及时处理缓冲区中的数据:
void ProcessThread::run()
{
while(mRunningState)
{
if(mWorkingState)
{
while(mSocket->hasPendingDatagrams())
{
QNetworkDatagram datagram = mSocket->receiveDatagram();
SocketCom::udpFrameProcessor->ReceivePackage(datagram.data());
}
mWorkingState = false;
}
}
}
当触发readyRead信号后将mWorkingState置为真。问题解决。
后续测试时发现,每次第一包数据总是接收不正确,后续数据都能正常接收。
我的一包数据包括7个子包,测试时发现第一包数据总是第1个子包先到,后6个子包后到,而后续数据都是7个子包一起到,遇到这种情况mWorkingState标志就会导致程序错误,因此改成如下:
void ProcessThread::run()
{
/*外层循环主要控制线程结束*/
while(mRunningState)
{
while(mSocket->hasPendingDatagrams())
{
/*在hasPendingDatagrams()和receiveDatagram()之间要加一个延时,
* 否则可能取不到第一帧数据*/
QThread::msleep(1);
QNetworkDatagram datagram = mSocket->receiveDatagram();
SocketCom::udpFrameProcessor->ReceivePackage(datagram.data());
}
}
}
这样子线程就在不断判断是否有数据,不再使用ReadyRead信号触发判断是否有数据,设计模式上就是从使用信号槽机制的回调模式改为不停判断的监听模式。
在while循环里的sleep是必须要加的,如果不加就会造成运行后CPU占用率100%的问题。一定要运行sleep将时间片让出去一下,处理其他事物。