QT做UDP组播,一行长度为248,全帧长度为248*128,从某个地址接收的每一包的行数不固定,子帧同步码F1F330,副帧同步码0230DF,将接收的每一包都先缓存起来并判断每一行的长度是否是正确的以及子帧或副帧同步码是否正确,在判断收到副帧同步码时打包发出给另一地址,给出代码及注释
时间: 2024-03-27 19:40:30 浏览: 51
下面是一个基于Qt的UDP组播接收程序,支持缓存和解析每个数据包,并判断每一行的长度和同步码是否正确,最终根据副帧同步码打包并发送给指定地址:
```c++
#include <QUdpSocket>
#include <QHostAddress>
#include <QByteArray>
#define ROW_LENGTH 248
#define FRAME_LENGTH (ROW_LENGTH * 128)
#define SUBFRAME_SYNC_CODE 0xF1F330
#define FRAME_SYNC_CODE 0x0230DF
class UdpReceiver : public QObject
{
Q_OBJECT
public:
UdpReceiver(QObject *parent = nullptr) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
// 绑定到组播地址和端口
udpSocket->bind(QHostAddress("224.0.0.1"), 8000, QUdpSocket::ShareAddress);
// 加入组播组
udpSocket->joinMulticastGroup(QHostAddress("224.0.0.1"));
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
}
private slots:
void processPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
// 读取数据包
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress senderAddress;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort);
// 解析数据包
parseDatagram(datagram);
}
}
private:
QUdpSocket *udpSocket;
QByteArray buffer; // 数据包缓存
bool hasSubframeSyncCode = false; // 是否找到子帧同步码
bool hasFrameSyncCode = false; // 是否找到副帧同步码
void parseDatagram(const QByteArray &datagram)
{
// 将数据包添加到缓存中
buffer.append(datagram);
// 如果缓存中的数据长度小于一帧的长度,则继续等待数据
if (buffer.length() < FRAME_LENGTH) {
return;
}
// 查找子帧同步码
if (!hasSubframeSyncCode) {
int idx = buffer.indexOf((char *)&SUBFRAME_SYNC_CODE, sizeof(SUBFRAME_SYNC_CODE));
if (idx != -1) {
buffer.remove(0, idx);
hasSubframeSyncCode = true;
} else {
buffer.clear();
return;
}
}
// 查找副帧同步码
if (!hasFrameSyncCode) {
int idx = buffer.indexOf((char *)&FRAME_SYNC_CODE, sizeof(FRAME_SYNC_CODE));
if (idx != -1) {
buffer.remove(0, idx);
hasFrameSyncCode = true;
} else {
buffer.clear();
return;
}
}
// 检查每一行的长度和同步码是否正确
int rowStart = 0;
int rowEnd = ROW_LENGTH;
while (rowEnd <= buffer.length()) {
// 检查行长度是否正确
if (buffer.mid(rowStart, ROW_LENGTH).length() != ROW_LENGTH) {
buffer.clear();
hasSubframeSyncCode = false;
hasFrameSyncCode = false;
return;
}
// 检查同步码是否正确
quint32 syncCode = *(quint32 *)(buffer.data() + rowStart);
if (syncCode != SUBFRAME_SYNC_CODE && syncCode != FRAME_SYNC_CODE) {
buffer.clear();
hasSubframeSyncCode = false;
hasFrameSyncCode = false;
return;
}
// 如果检测到副帧同步码,则打包并发送出去
if (syncCode == FRAME_SYNC_CODE) {
QByteArray frame = buffer.mid(rowStart, FRAME_LENGTH);
udpSocket->writeDatagram(frame, QHostAddress("192.168.1.100"), 8000);
}
rowStart = rowEnd;
rowEnd += ROW_LENGTH;
}
// 清空缓存并重置同步码状态
buffer.clear();
hasSubframeSyncCode = false;
hasFrameSyncCode = false;
}
};
```
在此代码中,我们定义了一个`UdpReceiver`类,作为UDP组播接收程序的主体,其中:
- `ROW_LENGTH`和`FRAME_LENGTH`分别定义了每行数据的长度和一帧数据的长度;
- `SUBFRAME_SYNC_CODE`和`FRAME_SYNC_CODE`分别定义了子帧同步码和副帧同步码;
- `udpSocket`成员变量是一个`QUdpSocket`对象,用于接收和发送UDP数据包;
- `buffer`成员变量是一个`QByteArray`对象,用于缓存接收到的数据包;
- `hasSubframeSyncCode`和`hasFrameSyncCode`分别表示是否已经找到了子帧同步码和副帧同步码;
在类的构造函数中,我们创建了一个`QUdpSocket`对象,并将其绑定到组播地址和端口,然后加入了组播组,并且将`readyRead`信号连接到了`processPendingDatagrams`槽函数。
`processPendingDatagrams`函数中,我们首先读取UDP数据包,然后调用`parseDatagram`函数对数据包进行解析和处理。
`parseDatagram`函数中,我们首先将数据包添加到缓存中,然后查找子帧同步码和副帧同步码。如果没有找到子帧同步码,则继续等待数据;如果没有找到副帧同步码,则继续等待数据。
如果已经找到了副帧同步码,则按照每行数据的长度和同步码检查数据包的正确性,如果出现错误则清空缓存并重置同步码状态。如果检测到副帧同步码,则将整个副帧数据打包并发送给指定地址。
这是一个比较基础的UDP组播接收程序,可以根据具体需求进行修改和扩展。
阅读全文