#ifndef MYUDP_H
#define MYUDP_H
#include <QObject>
#include <QUdpSocket>
class myudp:public QObject
{
Q_OBJECT
public:
explicit myudp(QObject *parent =nullptr);
QUdpSocket*getUdpSocket();
bool bindSockInfo(QString ip,quint16 port);
signals:
void recvMsg(QByteArray);
public slots:
void readSocket();
void sendMsg(QByteArray msg);
private:
QUdpSocket *m_sock;
QString m_ip;
quint16 m_port;
QHostAddress dest_ip;
quint16 dest_port;
};
#endif // MYUDP_H
#include "myudp.h"
#include <QHostAddress>
myudp::myudp(QObject *parent):QObject(parent)
{
m_sock=new QUdpSocket(this);
connect(m_sock,SIGNAL(readyRead()),this,SLOT(readSocket()));
}
QUdpSocket *myudp::getUdpSocket()
{
return m_sock;
}
bool myudp::bindSockInfo(QString ip, quint16 port)
{
return m_sock->bind(QHostAddress(ip),port);
}
void myudp::readSocket()
{
/*QByteArray data;
qint64 size=m_sock->pendingDatagramSize();
data.resize(size);
m_sock->readDatagram(data.data(),size,&dest_ip,&dest_port);
emit recvMsg(data);
*/
while (m_sock->hasPendingDatagrams()) {
QByteArray data;
qint64 size = m_sock->pendingDatagramSize();
data.resize(size);
QHostAddress sender;
quint16 senderPort;
m_sock->readDatagram(data.data(), size, &sender, &senderPort);
// 更新最后通信方
dest_ip = sender;
dest_port = senderPort;
emit recvMsg(data);
}
}
void myudp::sendMsg(QByteArray msg)
{
m_sock->writeDatagram(msg,dest_ip,dest_port);
}
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
class mytcpserver:public QObject
{
Q_OBJECT
public:
explicit mytcpserver(QObject *parent = nullptr);
~mytcpserver();
bool startServer(QString ip, quint16 port); // 启动服务器
void stopServer(); // 停止服务器
signals:
void recvMsg(QByteArray data); // 接收到客户端数据
void clientConnected(QString info); // 客户端连接
void clientDisconnected(QString info); // 客户端断开
public slots:
void sendData(QByteArray data); // 发送数据给所有客户端
private slots:
void onNewConnection(); // 新客户端接入
void onClientReadyRead(); // 客户端有数据到来
void onClientDisconnected(); // 客户端断开
private:
QTcpServer *m_server;
QList<QTcpSocket*> m_clients; // 管理多个客户端
QHostAddress getLocalIP(QString ip); // 解析本地地址
};
#endif // MYTCPSERVER_H
#include "mytcpserver.h"
#include <QHostAddress>
#include <QDebug>
mytcpserver::mytcpserver(QObject *parent)
: QObject(parent), m_server(new QTcpServer(this))
{
connect(m_server, &QTcpServer::newConnection, this, &mytcpserver::onNewConnection);
}
mytcpserver::~mytcpserver()
{
stopServer();
}
QHostAddress mytcpserver::getLocalIP(QString ip)
{
if (ip == "0.0.0.0" || ip.isEmpty() || ip == "localhost")
return QHostAddress::AnyIPv4;
return QHostAddress(ip);
}
bool mytcpserver::startServer(QString ip, quint16 port)
{
QHostAddress address = getLocalIP(ip);
if (m_server->isListening()) {
qDebug() << "Server already running.";
return true;
}
bool ok = m_server->listen(address, port);
if (ok) {
qDebug() << "TCP Server started:" << ip << ":" << port;
emit clientConnected("Server started at " + ip + ":" + QString::number(port));
} else {
qWarning() << "Listen failed:" << m_server->errorString();
}
return ok;
}
void mytcpserver::stopServer()
{
for (auto socket : m_clients) {
if (socket->state() == QAbstractSocket::ConnectedState)
socket->close();
socket->deleteLater();
}
m_clients.clear();
if (m_server->isListening()) {
m_server->close();
qDebug() << "TCP Server stopped.";
}
}
void mytcpserver::onNewConnection()
{
while (m_server->hasPendingConnections()) {
QTcpSocket *client = m_server->nextPendingConnection();
m_clients.append(client);
QString peerInfo = client->peerAddress().toString() + ":" + QString::number(client->peerPort());
qDebug() << "Client connected:" << peerInfo;
emit clientConnected("Client connected: " + peerInfo);
connect(client, &QTcpSocket::readyRead, this, &mytcpserver::onClientReadyRead);
connect(client, &QTcpSocket::disconnected, this, &mytcpserver::onClientDisconnected);
}
}
void mytcpserver::onClientReadyRead()
{
QTcpSocket *client = qobject_cast<QTcpSocket*>(sender());
if (!client) return;
QByteArray data = client->readAll();
emit recvMsg(data);
}
void mytcpserver::onClientDisconnected()
{
QTcpSocket *client = qobject_cast<QTcpSocket*>(sender());
if (!client) return;
QString peerInfo = client->peerAddress().toString() + ":" + QString::number(client->peerPort());
qDebug() << "Client disconnected:" << peerInfo;
emit clientDisconnected("Client disconnected: " + peerInfo);
m_clients.removeOne(client);
client->deleteLater();
}
void mytcpserver::sendData(QByteArray data)
{
for (int i = 0; i < m_clients.size(); ++i) {
QTcpSocket *client = m_clients[i];
if (client && client->state() == QAbstractSocket::ConnectedState) {
client->write(data);
} else {
// 清理无效连接
m_clients.removeAt(i);
--i;
client->deleteLater();
}
}
}
#ifndef MYTCPCLIENT_H
#define MYTCPCLIENT_H
#include <QObject>
#include <QTcpSocket>
class mytcpclient:public QObject
{
Q_OBJECT
public:
explicit mytcpclient(QObject *parent=nullptr);
~mytcpclient();
bool connectToHost(QString ip, quint16 port);
void disconnectFromHost();
void sendData(QByteArray data);
signals:
void recvMsg(QByteArray data);
void connectedStatus(bool connected, QString reason);
private slots:
void onConnected();
void onDisconnected();
void onReadyRead();
private:
QTcpSocket *m_socket;
};
#endif // MYTCPCLIENT_H
#include "mytcpclient.h"
#include <QTcpSocket>
#include <QDebug>
mytcpclient::mytcpclient(QObject *parent)
: QObject(parent), m_socket(new QTcpSocket(this))
{
connect(m_socket, &QTcpSocket::connected, this, &mytcpclient::onConnected);
connect(m_socket, &QTcpSocket::disconnected, this, &mytcpclient::onDisconnected);
connect(m_socket, &QTcpSocket::readyRead, this, &mytcpclient::onReadyRead);
}
mytcpclient::~mytcpclient()
{
disconnectFromHost();
}
bool mytcpclient::connectToHost(QString ip, quint16 port)
{
if (m_socket->state() == QAbstractSocket::ConnectedState ||
m_socket->state() == QAbstractSocket::ConnectingState) {
return true; // 避免重复连接
}
m_socket->connectToHost(ip, port);
}
void mytcpclient::disconnectFromHost()
{
m_socket->disconnectFromHost();
}
void mytcpclient::sendData(QByteArray data)
{
if (m_socket->state() == QAbstractSocket::ConnectedState) {
m_socket->write(data);
} else {
qWarning() << "Not connected, cannot send data.";
emit connectedStatus(false, "Not connected");
}
}
void mytcpclient::onConnected()
{
qDebug() << "Connected to server";
emit connectedStatus(true, "Connected");
}
void mytcpclient::onDisconnected()
{
qDebug() << "Disconnected from server";
emit connectedStatus(false, "Disconnected");
}
void mytcpclient::onReadyRead()
{
QByteArray data = m_socket->readAll();
emit recvMsg(data);
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "myudp.h"
#include "mytcpclient.h"
#include "mytcpserver.h"
#include <QString>
#include <QByteArray>
#include <QVariant>
#include <QDebug>
#include <QStringList>
#include <QMap>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void createUdp();
void createTcpServer();
void createTcpClient();
void closeCurrentConnection();
enum CommMode {
MODE_UDP,
MODE_TCP_SERVER,
MODE_TCP_CLIENT
};
signals:
void sendMsg(QByteArray);
private slots:
void on_sendpushButton_clicked();
void comboxChanged(int index);
void recvMsg(QByteArray);
//接收区设置
void on_pushButton_8_clicked();//network send
void on_savefile_checkBox_stateChanged(int arg1);
void on_auto_checkBox_stateChanged(int arg1);
void on_hex_checkBox_stateChanged(int arg1);
void on_pause_checkBox_stateChanged(int arg1);
void on_savedata_pushButton_clicked();
void on_clear_pushButton_clicked();
private:
Ui::MainWindow *ui;
//network
myudp *m_udp=nullptr;
mytcpserver *m_tcpServer = nullptr;
mytcpclient *m_tcpClient = nullptr;
CommMode currentMode = MODE_UDP;
//接收区设置
bool m_hexDisplay=false;
bool m_pauseDisplay=false;
QFile m_logFile;
QStringList m_pendingMessages;
QString formatHex(const QByteArray &data);
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//ui->comboBox_6->addItem("UDP");
//ui->comboBox_6->addItem("TCP Sever");
//ui->comboBox_6->addItem("TCP Client");
ui->pushButton_8->setText("链接");
ui->pushButton_8->setAccessibleName("OFF");
connect(ui->comboBox_6,SIGNAL(currentIndexChanged(int)),
this,SLOT(comboxChanged(int)));
createUdp();
createTcpServer();
createTcpClient();
ui->recvtextEdit->setLineWrapMode(QTextEdit::WidgetWidth);
connect(ui->savefile_checkBox, &QCheckBox::stateChanged,
this, &MainWindow::on_savefile_checkBox_stateChanged);
connect(ui->auto_checkBox, &QCheckBox::stateChanged,
this, &MainWindow::on_auto_checkBox_stateChanged);
connect(ui->hex_checkBox, &QCheckBox::stateChanged,
this, &MainWindow::on_hex_checkBox_stateChanged);
connect(ui->pause_checkBox, &QCheckBox::stateChanged,
this, &MainWindow::on_pause_checkBox_stateChanged);
connect(ui->savedata_pushButton, &QPushButton::clicked,
this, &MainWindow::on_savedata_pushButton_clicked);
connect(ui->clear_pushButton, &QPushButton::clicked,
this, &MainWindow::on_clear_pushButton_clicked);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_sendpushButton_clicked()
{
QString data=ui->sendtextEdit->toPlainText();
emit sendMsg(data.toLocal8Bit());
}
void MainWindow::createUdp()
{
if (m_udp) delete m_udp;
m_udp=new myudp(this);
connect(this,SIGNAL(sendMsg(QByteArray)),m_udp,SLOT(sendMsg(QByteArray)));
connect(m_udp,SIGNAL(recvMsg(QByteArray)),this,SLOT(recvMsg(QByteArray)));
currentMode = MODE_UDP;
}
void MainWindow::createTcpServer()
{
if (m_tcpServer) delete m_tcpServer;
m_tcpServer = new mytcpserver(this);
connect(this, &MainWindow::sendMsg, m_tcpServer, &mytcpserver::sendData);
connect(m_tcpServer, &mytcpserver::recvMsg, this, &MainWindow::recvMsg);
connect(m_tcpServer, &mytcpserver::clientConnected, [&](const QString& info){
ui->recvtextEdit->append("[SERVER] " + info);
});
connect(m_tcpServer, &mytcpserver::clientDisconnected, [&](const QString& info){
ui->recvtextEdit->append("[SERVER] " + info);
});
currentMode = MODE_TCP_SERVER;
}
void MainWindow::createTcpClient()
{
if (m_tcpClient) delete m_tcpClient;
m_tcpClient = new mytcpclient(this);
connect(this, &MainWindow::sendMsg, m_tcpClient, &mytcpclient::sendData);
connect(m_tcpClient, &mytcpclient::recvMsg, this, &MainWindow::recvMsg);
connect(m_tcpClient, &mytcpclient::connectedStatus, [&](bool connected, const QString& reason){
QString status = connected ? "Connected" : "Disconnected";
ui->recvtextEdit->append(QString("[CLIENT] %1: %2").arg(status, reason));
});
currentMode = MODE_TCP_CLIENT;
}
void MainWindow::closeCurrentConnection()
{
switch(currentMode) {
case MODE_UDP:
if (m_udp) {
m_udp->getUdpSocket()->close();
}
break;
case MODE_TCP_SERVER:
if (m_tcpServer) {
m_tcpServer->stopServer();
}
break;
case MODE_TCP_CLIENT:
if (m_tcpClient) {
m_tcpClient->disconnectFromHost();
}
break;
}
}
void MainWindow::comboxChanged(int index)
{
closeCurrentConnection();
if(0==index){
createUdp();
}else if(1==index){
createTcpServer();
}else {
createTcpClient();
}
/*
// 关闭当前连接
switch(index) {
case 0: createUdp(); break;
case 1: createTcpServer(); break;
case 2: createTcpClient(); break;
}
*/
}
void MainWindow::recvMsg(QByteArray msg)
{
// ui->recvtextEdit->append(QString::fromLocal8Bit(msg));
// 写入文件(如果开启)
if (m_logFile.isOpen()) {
QTextStream out(&m_logFile);
out << (m_hexDisplay ? formatHex(msg) : QString::fromLocal8Bit(msg)) << "\n";
m_logFile.flush();
}
// 暂停显示则缓存
if (m_pauseDisplay) {
m_pendingMessages.append(m_hexDisplay ? formatHex(msg) : QString::fromLocal8Bit(msg));
return;
}
// 正常显示
ui->recvtextEdit->append(m_hexDisplay ? formatHex(msg) : QString::fromLocal8Bit(msg));
}
void MainWindow::on_pushButton_8_clicked()
{
/*
QString ip=ui->lineEdit_4->text();
quint16 port=ui->lineEdit_5->text().toShort();
if(ui->pushButton_8->accessibleName()=="OFF"){
m_udp->bindSockInfo(ip,port);
ui->pushButton_8->setText("断开");
ui->pushButton_8->setAccessibleName("ON");
}else if(ui->pushButton_8->accessibleName()=="ON"){
QUdpSocket*socket=m_udp->getUdpSocket();
socket->close();
ui->pushButton_8->setText("链接");
ui->pushButton_8->setAccessibleName("OFF");
}
*/
QString ip = ui->iplineEdit->text().trimmed();
bool ok;
quint16 port = ui->portlineEdit->text().toUShort(&ok);
if (ip.isEmpty()) {
QMessageBox::warning(this, "错误", "请输入 IP 地址!");
return;
}
if (!ok || port == 0) {
QMessageBox::warning(this, "错误", "请输入有效端口号(1-65535)!");
return;
}
QPushButton *btn = ui->pushButton_8;
QString state = btn->accessibleName();
if (state == "OFF") {
bool success = false;
switch(currentMode) {
case MODE_UDP:
success = m_udp->bindSockInfo(ip, port);
break;
case MODE_TCP_SERVER:
success = m_tcpServer->startServer(ip, port);
break;
case MODE_TCP_CLIENT:
success = m_tcpClient->connectToHost(ip, port);
break;
}
if (success) {
btn->setText("断开");
btn->setAccessibleName("ON");
} else {
QMessageBox::critical(this, "失败", "连接/启动失败,请检查设置。");
}
} else {
closeCurrentConnection();
btn->setText("链接");
btn->setAccessibleName("OFF");
}
}
//接收器设置
void MainWindow::on_savefile_checkBox_stateChanged(int arg1)
{
QString content = ui->recvtextEdit->toPlainText();
if (content.isEmpty()) return;
QString file = QFileDialog::getSaveFileName(this, "接收区显示内容另存为", "", "Text Files (*.txt)");
if (!file.isEmpty()) {
QFile f(file);
if (f.open(QIODevice::WriteOnly | QIODevice::Text))
f.write(content.toUtf8());
}
}
void MainWindow::on_auto_checkBox_stateChanged(int arg1)
{
ui->recvtextEdit->setLineWrapMode(arg1 ? QTextEdit::WidgetWidth : QTextEdit::NoWrap);
}
void MainWindow::on_hex_checkBox_stateChanged(int arg1)
{
m_hexDisplay=arg1;;
ui->recvtextEdit->clear();
}
void MainWindow::on_pause_checkBox_stateChanged(int arg1)
{
m_pauseDisplay=arg1;
if(!arg1&&m_pendingMessages.isEmpty()){
for(const QString &msg:m_pendingMessages)
ui->recvtextEdit->append(msg);
m_pendingMessages.clear();
}
}
void MainWindow::on_savedata_pushButton_clicked()
{
QString content = ui->recvtextEdit->toPlainText();
if (content.isEmpty()) return;
QString file = QFileDialog::getSaveFileName(this, "保存数据", "", "Text Files (*.txt)");
if (!file.isEmpty()) {
QFile f(file);
if (f.open(QIODevice::WriteOnly | QIODevice::Text))
f.write(content.toUtf8());
}
}
void MainWindow::on_clear_pushButton_clicked()
{
ui->recvtextEdit->clear();
}
QString MainWindow::formatHex(const QByteArray &data)
{
QString result;
for (uchar b : data)
result += QString("%1 ").arg(b, 2, 16, QLatin1Char('0')).toUpper();
return result.trimmed();
}
保留核心实现,去除冗余,检查代码中是否有需要修改的错误
最新发布