在一段时间内,由a向组播一直发送几类数据包,在这段时间里b通过组播同时接收这几类数据,并且不断的转发向另一个组播、边接收边显示接收的数据源码在界面中,并实时动态的将收的数据保存到本地文件中,数据接收和转发显示、存储要同时进行,用多线程实现
【以下回答由 GPT 生成】
以下是实现该功能的步骤和代码示例:
#include <QApplication>
#include <QMainWindow>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow mainWindow;
mainWindow.show();
return app.exec();
}
#include <QThread>
class ReceiverThread : public QThread
{
Q_OBJECT
public:
explicit ReceiverThread(QObject *parent = nullptr) : QThread(parent) {}
protected:
void run() override
{
// 在这里实现数据接收逻辑
}
};
#include <QThread>
class ForwarderThread : public QThread
{
Q_OBJECT
public:
explicit ForwarderThread(QObject *parent = nullptr) : QThread(parent) {}
protected:
void run() override
{
// 在这里实现数据转发逻辑
}
};
#include <QThread>
class SaverThread : public QThread
{
Q_OBJECT
public:
explicit SaverThread(QObject *parent = nullptr) : QThread(parent) {}
protected:
void run() override
{
// 在这里实现数据保存逻辑
}
};
#include <QApplication>
#include <QMainWindow>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow mainWindow;
mainWindow.show();
ReceiverThread receiverThread(&mainWindow);
receiverThread.start();
ForwarderThread forwarderThread(&mainWindow);
forwarderThread.start();
SaverThread saverThread(&mainWindow);
saverThread.start();
return app.exec();
}
通过以上步骤和代码示例,你可以实现在Qt中创建一个多线程应用程序,用于接收指定组播数据并实时显示在窗口中,同时将接收到的数据转发至另一个组播中,并将数据边接收边保存到本地文件中。以上示例中的数据接收逻辑、数据转发逻辑和数据保存逻辑需要根据你的具体需求进行实现。
【相关推荐】
#include <QtWidgets>
#include <QUdpSocket>
#include <QThread>
class DataReceiver : public QObject
{
Q_OBJECT
public:
explicit DataReceiver(QObject *parent = nullptr) : QObject(parent) {}
public slots:
void receiveData()
{
// 创建UDP套接字并绑定到组播地址和端口
QUdpSocket socket;
socket.bind(QHostAddress::AnyIPv4, 1234);
// 加入组播组
socket.joinMulticastGroup(QHostAddress("224.0.0.1"));
while (true) {
QByteArray datagram;
datagram.resize(socket.pendingDatagramSize());
socket.readDatagram(datagram.data(), datagram.size());
// 处理接收到的数据
// ...
// 转发数据到另一个组播地址
socket.writeDatagram(datagram, QHostAddress("224.0.0.2"), 1235);
// 发送信号通知主线程更新界面
emit dataReceived(datagram);
}
}
signals:
void dataReceived(const QByteArray &data);
};
class DataStorage : public QObject
{
Q_OBJECT
public:
explicit DataStorage(QObject *parent = nullptr) : QObject(parent) {}
public slots:
void saveData(const QByteArray &data)
{
// 将接收到的数据保存到本地文件
QFile file("data.txt");
if (file.open(QIODevice::Append)) {
file.write(data);
file.close();
}
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
{
// 创建界面控件
QLabel *label = new QLabel(this);
QTextEdit *textEdit = new QTextEdit(this);
// 布局界面
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(label);
layout->addWidget(textEdit);
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
// 创建数据接收和存储的对象
DataReceiver *receiver = new DataReceiver(this);
DataStorage *storage = new DataStorage(this);
// 创建接收数据的线程
QThread *receiverThread = new QThread(this);
receiver->moveToThread(receiverThread);
connect(receiverThread, &QThread::started, receiver, &DataReceiver::receiveData);
connect(receiver, &DataReceiver::dataReceived, this, [=](const QByteArray &data) {
// 在主线程更新界面
label->setText(QString("Received: %1").arg(QString(data)));
});
connect(receiver, &DataReceiver::dataReceived, storage, &DataStorage::saveData);
receiverThread->start();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
#include "main.moc"
该示例代码使用Qt的多线程功能创建了两个线程,一个用于数据接收,另一个用于数据存储。数据接收线程通过UDP套接字接收组播数据,并将接收到的数据转发到另一个组播地址。同时,接收到的数据也会通过信号通知主线程更新界面,并实时将数据保存到本地文件中。
请注意,这只是一个示例代码,具体的实现可能需要根据您的需求进行修改和调整。您可以根据自己的实际情况,调整数据的处理逻辑、界面显示和文件保存方式等。
另外,请确保在使用Qt的多线程功能时,遵循Qt的线程安全规则,例如避免在多个线程中同时访问和修改同一数据。
使用C++实现UDP接收、转发和存储的完整示例代码:
cpp
Copy Code
#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <chrono>
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
const int BUFFER_SIZE = 1024; // 接收缓冲区大小
// 接收数据线程函数
void receiveData()
{
// 创建UDP socket
int udpSocket;
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cerr << "Failed to initialize Winsock" << std::endl;
return;
}
udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
#endif
// 设置接收端口和IP地址
int port = 12345; // 设置UDP接收端口
std::string ip = "127.0.0.1"; // 设置组播IP地址
struct sockaddr_in localAddress;
localAddress.sin_family = AF_INET;
localAddress.sin_port = htons(port);
localAddress.sin_addr.s_addr = inet_addr(ip.c_str());
// 将socket绑定到本地地址
if (bind(udpSocket, (struct sockaddr*)&localAddress, sizeof(localAddress)) == -1)
{
std::cerr << "Failed to bind socket" << std::endl;
#ifdef _WIN32
closesocket(udpSocket);
#else
close(udpSocket);
#endif
return;
}
// 接收数据并转发
char buffer[BUFFER_SIZE];
while (true)
{
// 接收UDP数据包
struct sockaddr_in clientAddress;
socklen_t clientAddressLength = sizeof(clientAddress);
memset(buffer, 0, BUFFER_SIZE); // 清空接收缓冲区
int bytesRead = recvfrom(udpSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&clientAddress, &clientAddressLength);
if (bytesRead <= 0)
{
std::cerr << "Failed to receive data" << std::endl;
continue;
}
// 将接收的数据源码在窗口中显示
std::cout << "Received Data: " << buffer << std::endl;
// 转发至另一个组播
int forwardPort = 23456; // 设置转发的组播端口
std::string forwardIp = "127.0.0.1"; // 设置转发的组播IP地址
struct sockaddr_in forwardAddress;
forwardAddress.sin_family = AF_INET;
forwardAddress.sin_port = htons(forwardPort);
forwardAddress.sin_addr.s_addr = inet_addr(forwardIp.c_str());
if (sendto(udpSocket, buffer, bytesRead, 0, (struct sockaddr*)&forwardAddress, sizeof(forwardAddress)) == -1)
{
std::cerr << "Failed to forward data" << std::endl;
continue;
}
// 将接收的数据保存到本地文件
std::ofstream file("received_data.txt", std::ios::app);
if (file.is_open())
{
file << buffer << std::endl;
file.close();
}
// 等待一段时间再继续接收数据
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
// 关闭UDP socket
#ifdef _WIN32
closesocket(udpSocket);
WSACleanup();
#else
close(udpSocket);
#endif
}
int main()
{
// 创建接收数据的线程
std::thread receiveThread(receiveData);
// 主线程执行其他任务
// 等待问题结题日期
std::this_thread::sleep_until(std::chrono::system_clock::time_point(std::chrono::seconds(1669059200))); // 结题日期为2022-08-22 00:00:00
// 结束接收数据线程
receiveThread.join();
return 0;
}
注意,在Windows平台上,需要链接ws2_32.lib库文件(在代码中使用了#pragma comment(lib, "ws2_32.lib")),并在程序开始前调用WSAStartup函数进行Winsock库的初始化,并在程序结束后调用WSACleanup函数释放资源
下面这是基于java实现的题主思路,题主根据自己的ip和请求更改接口定义可以进行实现,希望可以帮到您
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.*;
public class MulticastReceiver {
public static void main(String[] args) {
// 设置接收组播数据的地址和端口
String multicastAddress = "224.0.0.1";
int multicastPort = 8888;
// 设置转发组播数据的地址和端口
String forwardAddress = "224.0.0.2";
int forwardPort = 9999;
// 创建接收组播数据的线程
Thread receiverThread = new Thread(() -> {
try {
InetAddress group = InetAddress.getByName(multicastAddress);
MulticastSocket multicastSocket = new MulticastSocket(multicastPort);
multicastSocket.joinGroup(group);
byte[] buffer = new byte[1024];
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
multicastSocket.receive(packet);
String receivedData = new String(packet.getData(), 0, packet.getLength());
// 在窗口中显示接收到的数据
System.out.println("Received from " + packet.getAddress() + ": " + receivedData);
// 转发数据至另一个组播
InetAddress forwardGroup = InetAddress.getByName(forwardAddress);
DatagramPacket forwardPacket = new DatagramPacket(packet.getData(), packet.getLength(), forwardGroup, forwardPort);
// 创建发送组播数据的socket
MulticastSocket forwardSocket = new MulticastSocket();
forwardSocket.setTimeToLive(1); // 设置TTL为1,确保数据只在本地网络内传播
forwardSocket.send(forwardPacket);
forwardSocket.close();
// 将接收的数据保存到本地文件
try (FileOutputStream fos = new FileOutputStream("received_data.txt", true)) {
fos.write(receivedData.getBytes());
fos.write("\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
// 启动接收组播数据的线程
receiverThread.start();
}
}
引用chatgpt内容作答:
你想实现一个多线程的程序,该程序能够同时进行以下操作:
1、以UDP方式接收指定源的组播数据。
2、在窗口中实时显示接收到的数据。
3、将接收到的数据转发到另一个组播地址。
4、边接收边将数据保存到本地文件中。
以下是一个Python代码示例,用于实现你所描述的功能。请注意,这只是一个简单的示例,实际场景中可能需要根据具体需求进行更详细的调整和优化。
import socket
import threading
import time
# UDP接收和转发的组播地址和端口
receive_multicast_group = ('224.0.0.1', 5000)
forward_multicast_group = ('224.0.0.2', 5001)
# 本地保存数据的文件名
output_file = 'received_data.txt'
# 创建UDP接收套接字
receive_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
receive_socket.bind(('', receive_multicast_group[1]))
receive_socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(receive_multicast_group[0]) + socket.inet_aton('0.0.0.0'))
# 创建UDP转发套接字
forward_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 创建窗口显示接收到的数据
def display_received_data():
while True:
try:
data, addr = receive_socket.recvfrom(1024)
print(f"Received: {data.decode('utf-8')} from {addr}")
except Exception as e:
print(f"Error in receiving data: {e}")
# 创建线程用于显示接收到的数据
display_thread = threading.Thread(target=display_received_data)
display_thread.start()
# 创建线程用于转发接收到的数据
def forward_received_data():
while True:
try:
data, addr = receive_socket.recvfrom(1024)
forward_socket.sendto(data, forward_multicast_group)
except Exception as e:
print(f"Error in forwarding data: {e}")
forward_thread = threading.Thread(target=forward_received_data)
forward_thread.start()
# 创建线程用于保存接收到的数据到本地文件
def save_received_data():
while True:
try:
data, _ = receive_socket.recvfrom(1024)
with open(output_file, 'a') as f:
f.write(f"{time.ctime()}: {data.decode('utf-8')}\n")
except Exception as e:
print(f"Error in saving data: {e}")
save_thread = threading.Thread(target=save_received_data)
save_thread.start()
# 主线程等待所有子线程完成
try:
display_thread.join()
forward_thread.join()
save_thread.join()
except KeyboardInterrupt:
print("Program terminated by user.")
# 关闭套接字
receive_socket.close()
forward_socket.close()
在这个示例中,我们创建了三个线程来分别处理数据的显示、转发和保存。每个线程都有一个死循环来持续执行相应的操作。请注意,这只是一个基本的框架,你可能需要根据具体需求进行更多的调整,例如添加适当的异常处理、退出机制以及线程间的同步等。
另外,请确保你的操作系统和网络环境允许组播通信,并根据实际情况调整组播地址和端口号。此外,记得根据需要修改代码,使其适应实际业务逻辑。
import socket
import threading
# 设置参数
source_group = "224.0.0.1" # 指定源组播地址
source_port = 5000 # 源组播端口
dest_group = "224.0.0.2" # 目标组播地址
dest_port = 6000 # 目标组播端口
buffer_size = 1024 # 缓冲区大小
output_file = "received_data.txt" # 保存接收数据的文件名
# 创建源组播套接字
source_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
source_sock.bind(('', source_port))
source_sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(source_group) + socket.inet_aton("0.0.0.0"))
# 创建目标组播套接字
dest_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
dest_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
dest_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
dest_address = (dest_group, dest_port)
# 创建窗口显示接收的数据
def display_received_data():
while True:
data, _ = source_sock.recvfrom(buffer_size)
print("Received:", data.decode())
# 启动窗口显示线程
display_thread = threading.Thread(target=display_received_data)
display_thread.start()
# 接收数据并转发至目标组播和保存到文件
while True:
data, addr = source_sock.recvfrom(buffer_size)
print("Received:", data.decode())
# 转发数据至目标组播
dest_sock.sendto(data, dest_address)
# 保存数据到文件
with open(output_file, 'a') as f:
f.write(data.decode() + '\n')
可以参考下,ip需要更改
#include <QtWidgets>
#include <QUdpSocket>
#include <QFile>
#include <QTextStream>
#include <QThread>
class UdpReceiver : public QObject
{
Q_OBJECT
public:
explicit UdpReceiver(QObject* parent = nullptr) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::AnyIPv4, 12345, QUdpSocket::ShareAddress);
connect(udpSocket, &QUdpSocket::readyRead, this, &UdpReceiver::processPendingDatagrams);
}
signals:
void dataReceived(const QByteArray& data);
private slots:
void processPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
emit dataReceived(datagram);
}
}
private:
QUdpSocket* udpSocket;
};
class UdpForwarder : public QObject
{
Q_OBJECT
public:
explicit UdpForwarder(QObject* parent = nullptr) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::AnyIPv4, 23456, QUdpSocket::ShareAddress);
}
public slots:
void forwardData(const QByteArray& data)
{
udpSocket->writeDatagram(data, QHostAddress("196.168.0.1"), 12345);
}
private:
QUdpSocket* udpSocket;
};
class DataProcessor : public QObject
{
Q_OBJECT
public:
explicit DataProcessor(QObject* parent = nullptr) : QObject(parent) {}
public slots:
void processData(const QByteArray& data)
{
// 在这里进行数据处理
// ...
// 发送显示接收的数据信号
emit displayData(data);
// 发送转发数据信号
emit forwardData(data);
// 发送保存数据到本地文件信号
emit saveData(data);
}
signals:
void displayData(const QByteArray& data);
void forwardData(const QByteArray& data);
void saveData(const QByteArray& data);
};
class ReceiverThread : public QThread
{
Q_OBJECT
public:
explicit ReceiverThread(QObject* parent = nullptr) : QThread(parent)
{
receiver = new UdpReceiver();
processor = new DataProcessor();
forwarder = new UdpForwarder();
connect(receiver, &UdpReceiver::dataReceived, processor, &DataProcessor::processData);
connect(processor, &DataProcessor::displayData, this, &ReceiverThread::displayData);
connect(processor, &DataProcessor::forwardData, forwarder, &UdpForwarder::forwardData);
connect(processor, &DataProcessor::saveData, this, &ReceiverThread::saveData);
}
signals:
void displayData(const QByteArray& data);
protected:
void run() override
{
exec();
}
private:
UdpReceiver* receiver;
UdpForwarder* forwarder;
DataProcessor* processor;
QFile file;
private slots:
void displayData(const QByteArray& data)
{
emit this->displayData(data);
}
void saveData(const QByteArray& data)
{
if (!file.isOpen())
{
QString fileName = QCoreApplication::applicationDirPath() + "/received_data.txt";
file.setFileName(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
qWarning() << "Failed to open file for writing";
return;
}
}
QTextStream stream(&file);
stream << QString(data) << endl;
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr) : QMainWindow(parent)
{
receiverThread = new ReceiverThread(this);
connect(receiverThread, &ReceiverThread::displayData, this, &MainWindow::appendToLog);
startButton = new QPushButton("Start", this);
connect(startButton, &QPushButton::clicked, this, &MainWindow::startReceiverThread);
logTextEdit = new QTextEdit(this);
logTextEdit->setReadOnly(true);
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(startButton);
layout->addWidget(logTextEdit);
QWidget* centralWidget = new QWidget(this);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
}
private slots:
void appendToLog(const QByteArray& data)
{
logTextEdit->append(QString(data));
}
void startReceiverThread()
{
receiverThread->start();
}
private:
ReceiverThread *receiverThread;
QPushButton* startButton;
QTextEdit* logTextEdit;
};
引用chatgpt
#include <QtWidgets>
#include <QUdpSocket>
#include <QThread>
class ReceiverThread : public QThread
{
Q_OBJECT
public:
explicit ReceiverThread(QObject *parent = nullptr) : QThread(parent) {}
void run() override
{
QUdpSocket socket;
socket.bind(QHostAddress::AnyIPv4, 1234);
while (!isInterruptionRequested()) {
QByteArray datagram;
datagram.resize(socket.pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket.readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
// 处理接收到的数据
emit dataReceived(sender.toString(), datagram);
// 转发数据
forwardSocket.writeDatagram(datagram, QHostAddress("224.0.0.2"), 1235);
// 保存数据到本地文件
saveFile.write(datagram);
}
}
signals:
void dataReceived(const QString &sender, const QByteArray &data);
public:
QUdpSocket forwardSocket;
QFile saveFile;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
{
receiverThread.forwardSocket.bind(QHostAddress::AnyIPv4, 1235);
connect(&receiverThread, &ReceiverThread::dataReceived, this, &MainWindow::onDataReceived);
receiverThread.saveFile.setFileName("data.txt");
receiverThread.saveFile.open(QIODevice::WriteOnly | QIODevice::Append);
receiverThread.start();
}
~MainWindow() override
{
receiverThread.quit();
receiverThread.wait();
}
private slots:
void onDataReceived(const QString &sender, const QByteArray &data)
{
// 在窗口中显示接收到的数据
QTextEdit *textEdit = new QTextEdit;
textEdit->setWindowTitle("Received from: " + sender);
textEdit->setPlainText(QString::fromUtf8(data));
textEdit->show();
}
private:
ReceiverThread receiverThread;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
需要详细代码请评论
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QUdpSocket>
#include <QFile>
// 数据接收线程
class ReceiverThread : public QThread
{
Q_OBJECT
public:
explicit ReceiverThread(QObject *parent = nullptr) : QThread(parent) {}
signals:
void dataReceived(const QByteArray &data);
protected:
void run() override {
// 创建UDP套接字
QUdpSocket socket;
socket.bind(QHostAddress::AnyIPv4, 1234); // 绑定接收端口
while (!isInterruptionRequested()) {
// 接收数据
QByteArray data;
data.resize(socket.pendingDatagramSize());
socket.readDatagram(data.data(), data.size());
// 发送数据接收信号
emit dataReceived(data);
}
}
可以使用Qt的QThread类来创建多个线程,分别用于数据接收、转发、存储和显示。你的需要用过需要接收、转发和存储三个线程。
可以参考:
https://blog.csdn.net/qq_43341440/article/details/118182567
或者:https://blog.csdn.net/m0_60259116/article/details/130566630
我们创建了一个多线程的UDP接收程序。UdpReceiver 类用于在一个独立的线程中进行UDP数据接收、显示、转发和保存操作,而 ReceiverThread 类则继承自 QThread,用于创建并管理接收线程。
主要流程如下:
UdpReceiver 类继承自 QObject,在构造函数中初始化UDP接收和发送套接字。通过连接 readyRead 信号来读取接收到的数据,然后将数据显示在窗口中、转发到另一个组播地址,并保存到文件中。
ReceiverThread 类继承自 QThread,在 run 函数中创建 UdpReceiver 实例并启动事件循环。
在 main 函数中,创建一个 QTextEdit 窗口用于显示接收到的数据。然后创建一个 ReceiverThread 实例,连接 newDataReceived 信号到窗口的 append 槽,从而将接收到的数据显示在窗口中。
以下是一个使用Qt和C++实现多线程UDP接收、显示、转发和保存组播数据的示例代码:
#include <QtWidgets/QApplication>
#include <QtWidgets/QTextEdit>
#include <QUdpSocket>
#include <QThread>
#include <QFile>
#include <QTextStream>
#include <QDebug>
class UdpReceiver : public QObject {
Q_OBJECT
public:
UdpReceiver(QObject* parent = nullptr) : QObject(parent) {
udpSocket.bind(QHostAddress::Any, RECV_PORT, QUdpSocket::ShareAddress);
udpSocket.joinMulticastGroup(QHostAddress(MULTICAST_GROUP));
connect(&udpSocket, &QUdpSocket::readyRead, this, &UdpReceiver::readPendingDatagrams);
}
signals:
void newDataReceived(const QString& data);
private slots:
void readPendingDatagrams() {
while (udpSocket.hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket.pendingDatagramSize());
QHostAddress sender;
udpSocket.readDatagram(datagram.data(), datagram.size(), &sender);
QString dataString = QString::fromUtf8(datagram);
emit newDataReceived(dataString);
sendSocket.writeDatagram(datagram, QHostAddress(SEND_MULTICAST_GROUP), SEND_PORT);
saveToFile(dataString);
}
}
void saveToFile(const QString& data) {
QFile file("received_data.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
QTextStream stream(&file);
stream << data << "\n";
}
}
private:
QUdpSocket udpSocket;
QUdpSocket sendSocket;
const QString MULTICAST_GROUP = "224.0.0.1";
const quint16 RECV_PORT = 5000;
const QString SEND_MULTICAST_GROUP = "224.0.0.2";
const quint16 SEND_PORT = 6000;
};
class ReceiverThread : public QThread {
Q_OBJECT
public:
ReceiverThread(QObject* parent = nullptr) : QThread(parent) {}
protected:
void run() override {
UdpReceiver receiver;
connect(&receiver, &UdpReceiver::newDataReceived, this, &ReceiverThread::handleNewData);
exec();
}
signals:
void newDataReceived(const QString& data);
private slots:
void handleNewData(const QString& data) {
emit newDataReceived(data);
}
};
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
QTextEdit textEdit;
textEdit.setWindowTitle("UDP Receiver");
textEdit.resize(400, 300);
textEdit.show();
ReceiverThread receiverThread;
receiverThread.start();
QObject::connect(&receiverThread, &ReceiverThread::newDataReceived, [&textEdit](const QString& data) {
textEdit.append(data);
});
return a.exec();
}
如果有问题,请提出;没有问题请采纳。
通常写代码的时候QObject派生类对象的创建是在主线程中,所以connect连接信号槽默认走得是主线程的事件循环,信号触发后槽函数会在主线程中执行槽函数,这样就等于没有跨线程接收。
如果需要在其他线程中执行槽函数,则需要通过在QThread::run()函数中创建对象并且执行QThread::exec()启动线程自己的事件循环;
又或者通过QObject::moveToThread,设定一个QThread对象执行事件循环并将一个自定义的QObject派生类对象强制转移到该线程中。
总而言之就是要在线程自己的事件循环中处理信号和槽函数的连接
QUdpSocket、QTcpSocket内部存在信号槽的连接,如果一个对象在两个拥有自己事件循环的线程中connect信号槽,则可能信号和槽对接不上,所以这两个对象甚至是其他的一些IO类都是不支持跨线程访问的。
但是它们的基类QAbstractSocket提供了QAbstractSocket::socketDescriptor()和QAbstractSocket::setSocketDescriptor()可以用于获取套接字描述符和设置套接字描述符。所以你可以在两个线程外部创建一个QUdpSocket对象处理bind和加入组播组等操作,然后将其套接字描述符传入这两个线程中,再分别创建QUdpSocket对象并设置其套接字描述符,然后就可以实现跨线程的收发了。