文章目录
前言
基于VS2019、Qt5.15.5,纯代码实现两个Qt程序进行本地通信套接字(TCP/IP或UDP)。
效果
LocalTCP
步骤
先创建服务端程序,在创建客户端程序。
一、创建服务端程序
1. 思路
服务器端使用QTcpServer用于端口监听,建立服务器;QTcpSocket用于建立连接后使用套接字进行通信。创建之后,始终让服务器端处于监听状态。
具体地:
侦听固定端口50000的“QTcpServer”对象。
当客户端连接时,服务器会创建一个新的“QTcpSocket”对象来管理连接。
服务器将三个double值(采样率、采样长度和下采样率)作为“QByteArray”发送给客户端。
服务器侦听来自客户端的“启动”或“停止”命令,并相应地设置一个标志,触发相应操作。
当客户端断开连接时,服务器会将标志设置为false并记录消息
2. 代码
2.1 Server.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_Server.h"
#include <QTcpServer>
#include <QTcpSocket>
class Server : public QMainWindow
{
Q_OBJECT
public:
Server(QWidget *parent = nullptr);
~Server();
private:
Ui::ServerClass ui;
QTcpServer* server = nullptr; //监听
QTcpSocket* tcpSocket = nullptr; //通信套接字
bool startSendDataFlag = 0;
//QList<QTcpSocket*> clients; //暂时未用,后续多个客户端做准备
private slots:
void onDisconnected();
};
2.2 Server.cpp
#include "Server.h"
Server::Server(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
// 创建QTcpServer对象,并监听所有IP地址的50000端口
server = new QTcpServer(this);
server->listen(QHostAddress::Any, 50000);//Any可以换成LocalHost
qDebug() << "Server is listening...";
// 当有新连接时,执行lambda表达式
connect(server, &QTcpServer::newConnection, [=]() {
//取出建立好连接的套接字
tcpSocket = server->nextPendingConnection();
qDebug() << "Connected to client";
//发送服务器端的采样率、采样长度、降采样等double类型信息给客户端,进行初始化使用
double sampleRate = 1000.0; // replace with your sample rate
double sampleLength = 100.0; // replace with your sample length
double downSample = 2.0; // replace with your downsample rate
// 将上述参数打包成QByteArray发送
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
out << sampleRate << sampleLength << downSample;
tcpSocket->write(data); //写入数据到套接字
tcpSocket->flush(); // 刷新缓冲区,确保数据发送
// 当套接字有数据可读时,执行lambda表达式
connect(tcpSocket, &QTcpSocket::readyRead, [=]() {
//客户端会发送启动采集或停止采集给到服务器,服务器打开或者关闭startSendData
QByteArray falg = tcpSocket->readAll();// 读取所有数据
QString str(falg);// 将数据转换为字符串
if (str == "start") {
qDebug() << "Received start command from client";
startSendDataFlag = true;
qDebug() << "startSendDataFlag = " << startSendDataFlag;
}
else if (str == "stop") {
qDebug() << "Received stop command from client";
startSendDataFlag = false;
qDebug() << "startSendDataFlag = "<< startSendDataFlag;
}
});
// 当套接字断开连接时,调用onDisconnected槽函数
connect(tcpSocket, &QTcpSocket::disconnected, tcpSocket, &QTcpSocket::deleteLater);
connect(tcpSocket, &QTcpSocket::disconnected, this, &Server::onDisconnected);
});
}
Server::~Server()
{
if (tcpSocket) {
//tcpSocket->abort();
tcpSocket->deleteLater();
tcpSocket = nullptr;
}
if (server) {
server->deleteLater();
server = nullptr;
}
}
// 处理客户端断开连接的槽函数
void Server::onDisconnected()
{
//tcpSocket->deleteLater();
tcpSocket = nullptr;
if (startSendDataFlag) {
startSendDataFlag = false;
}
qDebug() << "Client disconnected";
qDebug() << "startSendDataFlag = "<< startSendDataFlag;
}
/*
*释放“QTcpSocket”对象分配的系统资源
*防止意外重复使用同一个插座
*允许在新客户端连接时重新创建套接字
*/
二、创建客户端程序
1. 思路
客户端GUI包括一个带有两个操作的工具栏:“连接到服务器”和“启动/停止”。
当用户单击“连接到服务器”时,客户端将创建一个新的“QTcpSocket”对象,并连接到位于“localhost:50000”的服务器。
建立连接后,客户端会设置一个标志并启用“启动/停止”操作。
当用户单击“启动/停止”时,客户端会向服务器发送“启动”或“停止”命令。
客户端从服务器接收三个双值,并将它们记录到控制台。
当客户端与服务器断开连接时,客户端会将标志设置为false并记录消息
2. 代码
2.1 Client.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_Client.h"
#include <QTcpSocket>
class Client : public QMainWindow
{
Q_OBJECT
public:
Client(QWidget *parent = nullptr);
~Client();
private slots:
void onConnected();
void onReadyRead();
void onDisconnected();
private:
Ui::ClientClass ui;
// 添加工具栏.
QToolBar* toolBar = nullptr;
QAction* connectServer = nullptr;
QAction* startReceive = nullptr;
QTcpSocket* socket = nullptr;
bool connectServerFlag = 0;
bool startReceiveFlag = 0;
double CsampleRate = 0;
double CsampleLength = 0;
double CdownSample = 0; //
};
2.2 Client.cpp
#include "Client.h"
Client::Client(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//qDebug() << "startReceiveFlag = " << startReceiveFlag;
connectServer = new QAction(QString::fromLocal8Bit("连接服务器"), this);
startReceive = new QAction(QString::fromLocal8Bit("启动"), this);
startReceive->setEnabled(false);
//socket = new QTcpSocket(this);
// 添加工具栏.
toolBar = new QToolBar(this);
// 指定停靠位置,如果第一个参数为Qt::LeftToolBarArea,就是停靠在左边的垂直工具栏.
addToolBar(Qt::TopToolBarArea, toolBar);
toolBar->setFloatable(true);// 设置允许浮动.
toolBar->setMovable(true); // 设置允许移动.
toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);// 设置工具栏按钮只有图片.
// 添加工具栏按钮.
toolBar->addAction(connectServer);
toolBar->addAction(startReceive);
//toolBar->addAction(blueAction);
// 添加分隔符.
toolBar->addSeparator();
//toolBar->addAction(microsoftYaHeiAction);
connect(connectServer, &QAction::triggered, this, [this] {
//
if (!connectServerFlag) {
qDebug() << "test1";
if (socket) {
socket->abort(); // cancel any existing connection attempt
socket->deleteLater(); // delete the existing socket
socket = nullptr;
qDebug() << "delete existed socket";
qDebug() << "please open server";
}
if (socket == nullptr) {
qDebug() << "new";
socket = new QTcpSocket(this);
}
//else {
//
//}
socket->connectToHost("localhost", 50000);
connect(socket, &QTcpSocket::connected, this, &Client::onConnected);
/*connect(socket, &QTcpSocket::disconnected, this, &Client::onDisconnected);
connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
socket->connectToHost("localhost", 50000);
qDebug() << "creat new socket";*/
}
else {
qDebug() << "test2";
socket->disconnectFromHost();
//onDisconnected(true);
/*connectServerFlag = false;
startReceiveFlag = false;
startReceive->setText(QString::fromLocal8Bit("启动"));
startReceive->setEnabled(false);
connectServer->setText(QString::fromLocal8Bit("连接服务器"));*/
//socket = nullptr;
}
});
connect(startReceive, &QAction::triggered, this, [this] {
if (connectServerFlag) {
//qDebug() << "startReceiveFlag = " << startReceiveFlag;
if (!startReceiveFlag) {
//qDebug() << "start";
QByteArray data;
data.append("start");
socket->write(data);
startReceiveFlag = true;
startReceive->setText(QString::fromLocal8Bit("停止"));
}
else {
//qDebug() << "stop";
QByteArray data;
data.append("stop");
socket->write(data);
startReceiveFlag = false;
startReceive->setText(QString::fromLocal8Bit("启动"));
}
}
else {
qDebug() << "请先与服务器连接";
}
});
/*socket = new QTcpSocket(this);
connect(socket, &QTcpSocket::connected, this, &Client::onConnected);
connect(socket, &QTcpSocket::readyRead, this, &Client::onReadyRead);
connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
socket->connectToHost("localhost", 50000);*/
}
Client::~Client()
{
// Delete the QTcpSocket object
if (socket) {
socket->abort(); // cancel any existing connection attempt
socket->deleteLater(); // delete the existing socket
socket = nullptr;
}
/*if (connectServer) {
delete connectServer;
connectServer = nullptr;
}
if (startReceive) {
delete startReceive;
startReceive = nullptr;
}*/
// Delete the GUI elements
/*if (toolBar) {
delete toolBar;
toolBar = nullptr;
}*/
}
void Client::onConnected()
{
qDebug() << "Connected to server";
connect(socket, &QTcpSocket::readyRead, this, &Client::onReadyRead);
connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
connect(socket, &QTcpSocket::disconnected, this, &Client::onDisconnected);
qDebug() << "creat new socket";
connectServerFlag = true;
startReceive->setEnabled(true);
connectServer->setText(QString::fromLocal8Bit("断开连接"));
}
void Client::onReadyRead() {
QByteArray data = socket->readAll();
QDataStream in(&data, QIODevice::ReadOnly);
in >> CsampleRate >> CsampleLength >> CdownSample;
qDebug() << "Received from server: "
<< "sampleRate:" << CsampleRate
<< ", sampleLength:" << CsampleLength
<< ", downSample:" << CdownSample;
}
void Client::onDisconnected()
{
qDebug() << "Client disconnected from server";
if (connectServerFlag) {
connectServerFlag = false;
}
if (startReceiveFlag) {
startReceiveFlag = false;
}
startReceive->setText(QString::fromLocal8Bit("启动"));
startReceive->setEnabled(false);
connectServer->setText(QString::fromLocal8Bit("连接服务器"));
socket = nullptr; // set socket to nullptr here
}
三、主函数和解决方案资源管理器
Server端
#include "Server.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Server w;
w.show();
return a.exec();
}
Client端
#include "Client.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Client w;
w.show();
return a.exec();
}
其他设置
为了代码能跑起来,下面是我的一些设置,请参考。
Network设置
两边程序的项目属性设置都要勾选
调试设置
- 为了看qDebug信息,设置控制台输出
代码和数据下载
我已经将我的代码和exe等文件上传,免费下载!支持开源!!
链接:https://pan.baidu.com/s/1-jn_o42HwzhpgvRBtPLM3w?pwd=yyds
提取码:yyds
–来自百度网盘超级会员V6的分享
总结
QTcpSocket对象的删除处理需要额外注意!