当前位置: 首页 > news >正文

【Qt网络编程基础】Tcp服务器和客户端(只支持一对一)

目录

一、编写思路

1、服务器

总体思路

详细思路

1. 构造函数 (Widget::Widget)

2. 启动监听 (Widget::on_btn_start_clicked)

3. 停止监听 (Widget::on_btn_cease_clicked)

4. 发送消息 (Widget::on_btn_info_clicked)

5. 接收消息 (Widget::receive_message)

6. 处理客户端连接状态变化 (Widget::handler_client_changed)

7. 处理新的客户端连接 (Widget::handler_newConnection)

2、客户端

总体思路

详细思路

1. 初始化客户端对象

2. 处理“连接服务端”按钮点击事件

3. 处理“断开服务端”按钮点击事件

4. 处理“发送消息”按钮点击事件

5. 处理接收到的消息

6. 处理连接状态变化

二、实现效果

1、服务器

2、客户端

三、完整代码

1、服务器

widget.h

widget.cpp

2、客户端

widget.h

widget.cpp



如需咨询请添加个人微信:a15135158368

欢迎叨扰,多多交流


一、编写思路

1、服务器

总体思路

/* 构建服务器的步骤* 1. 实例化服务器对象--QTcpServer*    相当于:socket* 2. 进入监听状态--listen*    相当于:bind + listen* 3. 监测客户端连接--newConnection*    newConnection信号* 4. 获得客户端连接--nextPendingConnection*    相当于:accept* 5. 读取客户端消息--readAll*    相当于:recv* 6. 发送数据--write*    相当于:send* 7. 关闭连接--disconnectFromHost*    相当于:close*/

详细思路

1. 构造函数 (Widget::Widget)

目的

  • 初始化窗口部件。

  • 创建并配置TCP服务器对象。

  • 连接信号与槽。

关键代码段

Widget::Widget(QWidget *parent): QWidget(parent)  // 调用基类构造函数, ui(new Ui::Widget)  // 初始化UI对象
{ui->setupUi(this);  // 设置UI界面this->setWindowTitle("服务器");  // 设置窗口标题this->resize(1024, 960);  // 设置窗口大小
​// 创建QTcpServer对象tcp_server = new QTcpServer(this);
​// 连接QTcpServer的newConnection信号到槽函数connect(tcp_server, &QTcpServer::newConnection, this, &Widget::handler_newConnection);
​// QT4写法(不推荐):老式信号与槽连接// connect(tcpServer, SIGNAL(newConnection()), this, SLOT(handler_newConnection()));
}
2. 启动监听 (Widget::on_btn_start_clicked)

目的

  • 启动TCP服务器,开始监听客户端连接请求。

  • 绑定IP地址和端口号。

关键代码段

void Widget::on_btn_start_clicked()
{// 使TCP服务器进入监听状态if (tcp_server->listen(QHostAddress(IP), PORT)){ui->te_content->append("服务器开始监听...");  // 显示成功消息}else{ui->te_content->append("服务器监听失败");  // 显示失败消息}
}
3. 停止监听 (Widget::on_btn_cease_clicked)

目的

  • 停止TCP服务器的监听。

  • 关闭服务器连接。

关键代码段

void Widget::on_btn_cease_clicked()
{tcp_server->close();  // 关闭TCP服务器ui->te_content->append("服务器已停止监听");  // 显示停止消息// 服务器关闭后,更新UI按钮状态
}
4. 发送消息 (Widget::on_btn_info_clicked)

目的

  • 向所有已连接的客户端发送消息。

关键代码段

void Widget::on_btn_info_clicked()
{// 获取所有已连接的客户端QList<QTcpSocket*> clients = tcp_server->findChildren<QTcpSocket*>();
​// 遍历每个客户端for (int i = 0; i < clients.length(); i++){QTcpSocket *client = clients[i];
​// 检查客户端的连接状态if (client->state() == QAbstractSocket::ConnectedState){// 发送消息client->write(ui->le_info->text().toUtf8());}else{// 如果客户端未连接,显示提示信息ui->te_content->append("客户端未连接,无法发送消息");}}
}
5. 接收消息 (Widget::receive_message)

目的

  • 处理接收到的客户端消息,并在文本框中显示。

关键代码段

void Widget::receive_message()
{QTcpSocket *client_socket = qobject_cast<QTcpSocket*>(sender());  // 获取发信的客户端套接字if (client_socket){QByteArray data = client_socket->readAll();  // 读取客户端发送的数据ui->te_content->append("客户端 : " + QString(data));  // 显示消息}
}
6. 处理客户端连接状态变化 (Widget::handler_client_changed)

目的

  • 处理客户端连接状态的变化,例如断开连接或连接成功。

  • 更新UI按钮状态。

关键代码段

void Widget::handler_client_changed(QAbstractSocket::SocketState socket_state)
{QTcpSocket *client_socket = (QTcpSocket*)sender();  // 获取发信的客户端套接字
​if (!client_socket) return;
​// 根据连接状态进行处理switch (socket_state){case QAbstractSocket::UnconnectedState:  // 客户端断开连接ui->te_content->append("客户端断开连接");  // 显示断开连接信息client_socket->deleteLater();  // 删除客户端套接字对象ui->btn_start->setEnabled(true);  // 启用“开始监听”按钮ui->btn_cease->setEnabled(false);  // 禁用“停止监听”按钮ui->btn_info->setEnabled(false);  // 禁用“发送消息”按钮break;
​case QAbstractSocket::ConnectedState:  // 客户端已连接ui->btn_start->setEnabled(false);  // 禁用“开始监听”按钮ui->btn_cease->setEnabled(true);  // 启用“停止监听”按钮ui->btn_info->setEnabled(true);  // 启用“发送消息”按钮ui->te_content->append("客户端已连接");  // 显示连接成功信息break;
​default:break;}
}
7. 处理新的客户端连接 (Widget::handler_newConnection)

目的

  • 处理新客户端的连接请求。

  • 获取客户端的IP地址和端口号。

  • 连接相关的信号和槽,处理客户端的消息和状态变化。

关键代码段

void Widget::handler_newConnection()
{// 获取新的客户端连接QTcpSocket *client_socket = tcp_server->nextPendingConnection();
​// 错误处理:检查是否成功获取客户端连接if (client_socket == nullptr){ui->te_content->append("错误:无法获取客户端连接");  // 显示错误信息qDebug() << "Error: Failed to get new client connection.";return;  // 获取失败,直接返回}
​ui->btn_start->setEnabled(false);  // 禁用“开始监听”按钮ui->btn_cease->setEnabled(true);  // 启用“停止监听”按钮ui->btn_info->setEnabled(true);  // 启用“发送消息”按钮
​// 获取客户端的IP地址和端口号QString ip_addr = client_socket->peerAddress().toString();quint16 port = client_socket->peerPort();
​// 错误处理:检查是否成功获取IP地址和端口号if (ip_addr.isEmpty() || port == 0) {ui->te_content->append("错误:无法获取客户端的IP地址或端口号");  // 显示错误信息qDebug() << "Error: Failed to get client's IP address or port.";client_socket->disconnectFromHost();  // 断开连接client_socket->deleteLater();  // 删除客户端套接字对象return;  // 获取失败,直接返回}
​// 打印客户端的IP地址和端口号ui->te_content->append("客户端的IP地址为: " + ip_addr);ui->te_content->append("客户端的端口号为: " + QString::number(port));
​// 连接信号与槽,处理客户端的消息和状态变化connect(client_socket, &QTcpSocket::readyRead, this, &Widget::receive_message);connect(client_socket, &QTcpSocket::stateChanged, this, &Widget::handler_client_changed);
​// 错误处理:处理客户端的异常断开情况connect(client_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),this, [=](QAbstractSocket::SocketError socketError){ui->te_content->append("错误:客户端连接错误,错误代码:" + QString::number(socketError));  // 显示错误信息qDebug() << "Client connection error, error code: " << socketError;client_socket->deleteLater();  // 删除客户端套接字对象});
}

2、客户端

总体思路

/** 客户端构建步骤:* 1、实例化QTcpSocket对象* 2、连接服务器--connectToHost* 3、判断是否连接成功--waitForConnected* 4、连接对端接收信号--readyRead* 5、发送数据--write* 6、关闭连接--disconnectFromHost*/

详细思路

1. 初始化客户端对象
  • 步骤

    创建 QTcpSocket 对象,设置 UI 界面,并连接信号与槽函数。

  • 关键代码段:

    Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
    {ui->setupUi(this);  // 设置UI界面this->setWindowTitle("-客户端-");  // 设置窗口标题this->resize(1024, 960);  // 设置窗口大小
    ​tcp_socket = new QTcpSocket(this);  // 创建QTcpSocket对象
    ​// 连接QTcpSocket的信号与槽函数connect(tcp_socket, &QTcpSocket::readyRead, this, &Widget::receiveMessage);connect(tcp_socket, &QTcpSocket::stateChanged, this, &Widget::mStateChanged);
    }
  • 详细说明:

    • ui->setupUi(this): 初始化UI界面。

    • tcp_socket = new QTcpSocket(this): 创建TCP套接字对象,用于与服务器进行通信。

    • connect(): 连接QTcpSocket的信号readyReadstateChanged到对应的槽函数receiveMessagemStateChanged

2. 处理“连接服务端”按钮点击事件
  • 步骤

    调用 QTcpSocketconnectToHost() 方法来连接服务器。

  • 关键代码段:

    void Widget::on_btn_start_clicked()
    {// 尝试连接到指定的IP地址和端口号tcp_socket->connectToHost(QHostAddress(IP), PORT);
    }
  • 详细说明:

    • tcp_socket->connectToHost(QHostAddress(IP), PORT): 连接到指定的IP地址和端口号。此函数异步执行,连接成功或失败将触发相应的信号。

3. 处理“断开服务端”按钮点击事件
  • 步骤

    调用 QTcpSocketdisconnectFromHost() 方法断开与服务器的连接。

  • 关键代码段:

    void Widget::on_btn_cease_clicked()
    {// 断开与服务器的连接tcp_socket->disconnectFromHost();
    }
  • 详细说明

    • tcp_socket->disconnectFromHost(): 断开与服务器的连接,释放资源。

4. 处理“发送消息”按钮点击事件
  • 步骤

    检查客户端是否已连接到服务器,然后发送消息。

  • 关键代码段:

    void Widget::on_btn_info_clicked()
    {// 检查当前是否处于连接状态if (tcp_socket->state() == QAbstractSocket::ConnectedState){// 发送消息到服务器tcp_socket->write(ui->le_info->text().toUtf8());}else{// 如果未连接,显示提示信息ui->te_content->append("请先连接服务器!");}
    }
  • 详细说明

    • tcp_socket->state() == QAbstractSocket::ConnectedState: 确保在发送消息之前客户端已连接到服务器。

    • tcp_socket->write(): 发送消息到服务器。消息需转换为字节数组(QByteArray)。

5. 处理接收到的消息
  • 步骤

    读取服务器发送的数据并显示在文本框中。

  • 关键代码段:

    void Widget::receiveMessage()
    {// 读取所有接收到的数据,并显示在文本框中ui->te_content->append("服务器发送的消息:" + tcp_socket->readAll());
    }
  • 详细说明:

    • tcp_socket->readAll(): 读取从服务器接收到的所有数据,并以字符串形式显示在文本框中。

6. 处理连接状态变化
  • 步骤

    根据连接状态的变化更新UI和显示状态信息。

  • 关键代码段:

    void Widget::mStateChanged(QAbstractSocket::SocketState socketstate)
    {switch (socketstate){case QAbstractSocket::UnconnectedState:ui->te_content->append("与服务器断开连接");ui->btn_start->setEnabled(true);   // 允许重新连接ui->btn_cease->setEnabled(false);  // 禁用断开按钮ui->btn_info->setEnabled(false);   // 禁用发送按钮break;
    ​case QAbstractSocket::ConnectedState:ui->te_content->append("与服务器建立连接");ui->btn_start->setEnabled(false);  // 禁用连接按钮ui->btn_cease->setEnabled(true);   // 允许断开ui->btn_info->setEnabled(true);    // 允许发送消息break;
    ​case QAbstractSocket::HostLookupState:ui->te_content->append("正在查找主机...");break;
    ​case QAbstractSocket::ConnectingState:ui->te_content->append("正在连接服务器...");break;
    ​case QAbstractSocket::ClosingState:ui->te_content->append("正在关闭连接...");break;
    ​default:// 显示未知状态的调试信息qDebug() << "未知的错误, 当前状态: " << socketstate;break;}
    }
  • 详细说明

    • 根据 socketstate 的不同值更新UI和显示状态信息。

    • QAbstractSocket::UnconnectedState: 客户端已断开连接。

    • QAbstractSocket::ConnectedState: 客户端已连接到服务器。

    • QAbstractSocket::HostLookupState, QAbstractSocket::ConnectingState, QAbstractSocket::ClosingState: 其他状态信息。

二、实现效果

1、服务器

2、客户端

三、完整代码

1、服务器

widget.h

#ifndef WIDGET_H
#define WIDGET_H
​
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>  // TCP服务器和客户端都使用
​
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
​
// Widget类继承自QWidget,是一个用于实现TCP服务器的界面
class Widget : public QWidget
{Q_OBJECT
​
public:// 构造函数,初始化Widget对象Widget(QWidget *parent = nullptr);
​// 析构函数,清理资源~Widget();
​
private slots:// 处理“开始”按钮点击事件的槽函数void on_btn_start_clicked();
​// 处理“停止”按钮点击事件的槽函数void on_btn_cease_clicked();
​// 处理“信息”按钮点击事件的槽函数void on_btn_info_clicked();
​// 处理接收到消息的槽函数void receive_message();
​// 处理客户端连接状态变化的槽函数void handler_client_changed(QAbstractSocket::SocketState socket_state);
​// 处理新的连接请求的槽函数void handler_newConnection();
​
private:// UI对象指针,用于管理界面组件Ui::Widget *ui;
​// TCP服务器对象指针QTcpServer *tcp_server;
};
​
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
​
const char* IP = "127.0.0.1";    // 定义IP地址常量,表示本地地址
const unsigned int PORT = 8888;  // 定义端口号常量,表示服务器监听的端口
​
/* 构建服务器的步骤* 1. 实例化服务器对象--QTcpServer*    相当于:socket* 2. 进入监听状态--listen*    相当于:bind + listen* 3. 监测客户端连接--newConnection*    newConnection信号* 4. 获得客户端连接--nextPendingConnection*    相当于:accept* 5. 读取客户端消息--readAll*    相当于:recv* 6. 发送数据--write*    相当于:send* 7. 关闭连接--disconnectFromHost*    相当于:close*/
​
/** te_content* btn_start btn_cease* btn_info le_info*/
​
/************************************************************ @函数名:Widget* @功  能:构造函数---创建服务端对象,与客户端连接* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)  // 初始化UI对象
{ui->setupUi(this);  // 设置UI界面this->setWindowTitle("服务器");  // 设置窗口标题this->resize(1024, 960);  // 设置窗口大小
​// 创建QTcpServer对象,用于监听客户端连接tcp_server = new QTcpServer(this);
​// 连接QTcpServer的newConnection信号到处理新的连接的槽函数connect(tcp_server, &QTcpServer::newConnection, this, &Widget::handler_newConnection);
​// QT4写法(不推荐使用):连接信号与槽的老式写法// connect(tcpServer, SIGNAL(newConnection()), this, SLOT(handler_newConnection()));
}
​
Widget::~Widget()
{delete ui;  // 删除UI对象,释放资源
}
​
/************************************************************ @函数名:on_btn_start_clicked()* @功  能:按钮"开始监听"的槽函数,开始监听服务器,绑定IP和端口* @参  数:无* @返回值:无*********************************************************/
void Widget::on_btn_start_clicked()
{// 进入监听状态,绑定IP和端口if (tcp_server->listen(QHostAddress(IP), PORT)){ui->te_content->append("服务器开始监听...");  // 在文本框中显示成功消息}else{ui->te_content->append("服务器监听失败");  // 在文本框中显示失败消息}
}
​
/************************************************************ @函数名:on_btn_cease_clicked()* @功  能:按钮"停止监听"的槽函数,停止监听并关闭服务器* @参  数:无* @返回值:无*********************************************************/
void Widget::on_btn_cease_clicked()
{tcp_server->close();  // 关闭TCP服务器ui->te_content->append("服务器已停止监听");  // 在文本框中显示停止消息// 服务器关闭后,相关UI按钮状态更新
}
​
/************************************************************ @函数名:on_btn_info_clicked()* @功  能:按钮"发送消息"的槽函数,将文本信息发送给所有客户端* @参  数:无* @返回值:无*********************************************************/
void Widget::on_btn_info_clicked()
{// 获取所有已连接的客户端QList<QTcpSocket*> clients = tcp_server->findChildren<QTcpSocket*>();
​// 遍历每个客户端for (int i = 0; i < clients.length(); i++){QTcpSocket *client = clients[i];
​// 检查客户端的连接状态if (client->state() == QAbstractSocket::ConnectedState){// 发送数据client->write(ui->le_info->text().toUtf8());}else{// 如果客户端未连接,输出信息提示ui->te_content->append("客户端未连接,无法发送消息");}}
}
​
/************************************************************ @函数名:receive_message* @功  能:槽函数:接收客户端发送的消息并在文本框中显示* @参  数:无* @返回值:无*********************************************************/
void Widget::receive_message()
{QTcpSocket *client_socket = qobject_cast<QTcpSocket*>(sender());  // 获取发信的客户端套接字if (client_socket){QByteArray data = client_socket->readAll();  // 读取客户端发送的所有数据ui->te_content->append("客户端 : " + QString(data));  // 在文本框中显示消息}
}
​
/************************************************************ @函数名:handler_client_changed* @功  能:槽函数:处理客户端连接状态的改变* @参  数:socketState---客户端连接状态* @返回值:无*********************************************************/
void Widget::handler_client_changed(QAbstractSocket::SocketState socket_state)
{QTcpSocket *client_socket = (QTcpSocket*)sender();  // 获取发信的客户端套接字
​if (!client_socket) return;
​// 根据连接状态进行处理switch (socket_state){case QAbstractSocket::UnconnectedState:  // 客户端断开连接ui->te_content->append("客户端断开连接");  // 在文本框中显示断开连接信息client_socket->deleteLater();  // 删除客户端套接字对象ui->btn_start->setEnabled(true);  // 启用“开始监听”按钮ui->btn_cease->setEnabled(false);  // 禁用“停止监听”按钮ui->btn_info->setEnabled(false);  // 禁用“发送消息”按钮break;
​case QAbstractSocket::ConnectedState:  // 客户端已连接ui->btn_start->setEnabled(false);  // 禁用“开始监听”按钮ui->btn_cease->setEnabled(true);  // 启用“停止监听”按钮ui->btn_info->setEnabled(true);  // 启用“发送消息”按钮ui->te_content->append("客户端已连接");  // 在文本框中显示连接成功信息break;
​default:break;}
}
​
/************************************************************ @函数名:handler_newConnection* @功  能:槽函数:当有新的客户端连接时,打印客户端IP和端口* @参  数:无* @返回值:无*********************************************************/
void Widget::handler_newConnection()
{// 获取新的客户端连接QTcpSocket *client_socket = tcp_server->nextPendingConnection();
​// 错误处理:检查是否成功获取客户端连接if (client_socket == nullptr){ui->te_content->append("错误:无法获取客户端连接");  // 在文本框中显示错误信息qDebug() << "Error: Failed to get new client connection.";return;  // 如果获取失败,直接返回}
​ui->btn_start->setEnabled(false);  // 禁用“开始监听”按钮ui->btn_cease->setEnabled(true);  // 启用“停止监听”按钮ui->btn_info->setEnabled(true);  // 启用“发送消息”按钮
​// 获取客户端的IP地址和端口号QString ip_addr = client_socket->peerAddress().toString();quint16 port = client_socket->peerPort();
​// 错误处理:检查是否成功获取IP地址和端口号if (ip_addr.isEmpty() || port == 0) {ui->te_content->append("错误:无法获取客户端的IP地址或端口号");  // 在文本框中显示错误信息qDebug() << "Error: Failed to get client's IP address or port.";client_socket->disconnectFromHost();  // 断开连接client_socket->deleteLater();  // 删除客户端套接字对象return;  // 如果获取失败,直接返回}
​// 打印客户端的IP地址和端口号ui->te_content->append("客户端的IP地址为: " + ip_addr);ui->te_content->append("客户端的端口号为: " + QString::number(port));
​// 处理接收数据的槽函数connect(client_socket, &QTcpSocket::readyRead, this, &Widget::receive_message);
​// 处理连接状态变化的槽函数connect(client_socket, &QTcpSocket::stateChanged, this, &Widget::handler_client_changed);
​// 错误处理:处理客户端的异常断开情况connect(client_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),this, [=](QAbstractSocket::SocketError socketError){ui->te_content->append("错误:客户端连接错误,错误代码:" + QString::number(socketError));  // 显示错误信息qDebug() << "Client connection error, error code: " << socketError;client_socket->deleteLater();  // 删除客户端套接字对象});
}

2、客户端

widget.h

#ifndef WIDGET_H
#define WIDGET_H
​
#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
​
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
​
// 定义Widget类,继承自QWidget
class Widget : public QWidget
{Q_OBJECT  // Qt的元对象系统宏,支持信号和槽
​
public:// 构造函数:初始化Widget对象// @param parent:父对象指针,默认为nullptrWidget(QWidget *parent = nullptr);
​// 析构函数:释放资源~Widget();
​
private slots:// 槽函数:处理点击"开始"按钮事件void on_btn_start_clicked();
​// 槽函数:处理点击"停止"按钮事件void on_btn_cease_clicked();
​// 槽函数:处理点击"发送信息"按钮事件void on_btn_info_clicked();
​// 槽函数:接收并处理来自客户端的消息void receive_message();
​// 槽函数:处理TCP连接状态改变事件// @param socketstate:连接状态void state_changed(QAbstractSocket::SocketState socketstate);
​
private:Ui::Widget *ui;  // 指向UI界面的指针
​QTcpSocket *tcp_socket;  // 指向TCP套接字对象的指针
};
​
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QTcpSocket>
#include <QHostAddress>
#include <QDebug>
​
const char* IP = "127.0.0.1";  // 定义服务器的IP地址
const unsigned int PORT = 8888;  // 定义服务器的端口号
​
/** 客户端构建步骤:* 1、实例化QTcpSocket对象* 2、连接服务器--connectToHost* 3、判断是否连接成功--waitForConnected* 4、连接对端接收信号--readyRead* 5、发送数据--write* 6、关闭连接--disconnectFromHost*/
​
/** te_content:文本框,用于显示接收到的消息和状态信息* btn_start:按钮,用于启动与服务器的连接* btn_cease:按钮,用于断开与服务器的连接* btn_info:按钮,用于发送消息到服务器* le_info:文本框,用于输入待发送的消息*/
​
/************************************************************ @函数名:Widget* @功  能:构造函数,初始化客户端界面和TCP套接字对象* @参  数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);  // 设置UI界面this->setWindowTitle("-客户端-");  // 设置窗口标题this->resize(1024, 960);  // 设置窗口大小
​tcp_socket = new QTcpSocket(this);  // 创建QTcpSocket对象
​// 连接QTcpSocket的信号与槽函数connect(tcp_socket, &QTcpSocket::readyRead, this, &Widget::receive_message);connect(tcp_socket, &QTcpSocket::stateChanged, this, &Widget::state_changed);
​// QT4写法(不推荐):老式信号与槽连接// connect(tcp_socket, SIGNAL(readyRead()), this, SLOT(receive_message()));// connect(tcp_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),//         this, SLOT(state_changed(QAbstractSocket::SocketState)));
}
​
/************************************************************ @函数名:~Widget* @功  能:析构函数,释放资源* @参  数:无* @返回值:无*********************************************************/
Widget::~Widget()
{delete ui;  // 删除UI对象
}
​
/************************************************************ @函数名:on_btn_start_clicked()* @功  能:处理点击“连接服务端”按钮的事件* @参  数:无* @返回值:无*********************************************************/
void Widget::on_btn_start_clicked()
{// 尝试连接到指定的IP地址和端口号tcp_socket->connectToHost(QHostAddress(IP), PORT);
}
​
/************************************************************ @函数名:on_btn_cease_clicked()* @功  能:处理点击“断开服务端”按钮的事件* @参  数:无* @返回值:无*********************************************************/
void Widget::on_btn_cease_clicked()
{// 断开与服务器的连接tcp_socket->disconnectFromHost();
}
​
/************************************************************ @函数名:on_btn_info_clicked()* @功  能:处理点击“发送消息”按钮的事件*        发送消息到服务器,只有在连接状态时才允许发送* @参  数:无* @返回值:无*********************************************************/
void Widget::on_btn_info_clicked()
{// 检查当前是否处于连接状态if (tcp_socket->state() == QAbstractSocket::ConnectedState){// 发送消息到服务器tcp_socket->write(ui->le_info->text().toUtf8());}else{// 如果未连接,显示提示信息ui->te_content->append("请先连接服务器!");}
}
​
/************************************************************ @函数名:receive_message* @功  能:槽函数---接收服务器发送的数据,并显示在文本框中* @参  数:无* @返回值:无*********************************************************/
void Widget::receive_message()
{// 读取所有接收到的数据,并显示在文本框中ui->te_content->append("服务器发送的消息:" + tcp_socket->readAll());
}
​
/************************************************************ @函数名:state_changed* @功  能:槽函数---处理客户端连接状态的改变* @参  数:socketstate---当前连接状态* @返回值:无*********************************************************/
void Widget::state_changed(QAbstractSocket::SocketState socketstate)
{// 根据不同的连接状态更新UI和显示状态信息switch (socketstate){case QAbstractSocket::UnconnectedState:ui->te_content->append("与服务器断开连接");ui->btn_start->setEnabled(true);   // 允许重新连接ui->btn_cease->setEnabled(false);  // 禁用断开按钮ui->btn_info->setEnabled(false);   // 禁用发送按钮break;
​case QAbstractSocket::ConnectedState:ui->te_content->append("与服务器建立连接");ui->btn_start->setEnabled(false);  // 禁用连接按钮ui->btn_cease->setEnabled(true);   // 允许断开ui->btn_info->setEnabled(true);    // 允许发送消息break;
​case QAbstractSocket::HostLookupState:ui->te_content->append("正在查找主机...");break;
​case QAbstractSocket::ConnectingState:ui->te_content->append("正在连接服务器...");break;
​case QAbstractSocket::ClosingState:ui->te_content->append("正在关闭连接...");break;
​default:// 显示未知状态的调试信息qDebug() << "未知的错误, 当前状态: " << socketstate;break;}
}

相关文章:

【Qt网络编程基础】Tcp服务器和客户端(只支持一对一)

目录 一、编写思路 1、服务器 总体思路 详细思路 1. 构造函数 (Widget::Widget) 2. 启动监听 (Widget::on_btn_start_clicked) 3. 停止监听 (Widget::on_btn_cease_clicked) 4. 发送消息 (Widget::on_btn_info_clicked) 5. 接收消息 (Widget::receive_message) 6. 处…...

平台开发到落地详解:从食堂采购系统源码到可视化供应链管理数据大屏

随着数字化转型的加速&#xff0c;越来越多的企业和组织开始重视供应链的智能化与可视化管理。在食堂采购领域&#xff0c;供应链管理的复杂性与日俱增&#xff0c;而传统的手工操作往往效率低下、容易出错。因此&#xff0c;开发食堂采购系统并结合可视化数据大屏的解决方案&a…...

静态内部类

目录 一、什么是静态内部类二、静态内部类的意义 一、什么是静态内部类 在 Java 中&#xff0c;静态内部类&#xff08;也称为静态嵌套类&#xff09;是定义在一个类内部的类&#xff0c;但它与外部类没有关联&#xff0c;即它不持有外部类的引用。静态内部类可以访问外部类的…...

Vue+SpringBoot+数据库整体开发流程 1

本篇文章通过springboot整合mybatis-plus去实现后端对数据库的增删改查&#xff0c;以及响应给前端的url&#xff0c;让前端获得数据。 目录 一、简单搭建一个Vue项目 检查node.js版本 使用vue-cli创建空项目 Vue-cli工程中每个文件夹和文件的用处 二、Mysql数据库 创建数…...

百度Apollo打通与ROS的通信,扩展自动驾驶系统生态

技术文档&#xff5c;打通与ROS的通信&#xff0c;扩展自动驾驶系统生态_Apollo开发者社区 (baidu.com)...

Web3 项目安全手册

现如今针对 Web3 项目的攻击手法层出不穷&#xff0c;且项目之间的交互也越发复杂&#xff0c;在各个项目之间的交互经常会引入新的安全问题&#xff0c;而大部分 Web3 项目研发团队普遍缺少的一线的安全攻防经验&#xff0c;并且在进行 Web3 项目研发的时候&#xff0c;重点关…...

AI边缘计算在安防领域的智能化革新:赋能安防系统的智能化升级

随着人工智能&#xff08;AI&#xff09;和边缘计算技术的快速发展&#xff0c;两者在安防视频领域的应用日益广泛&#xff0c;为传统安防系统带来了革命性的变革。AI边缘计算技术通过将AI算法和模型部署在边缘设备上&#xff0c;实现了数据处理和智能决策的即时响应&#xff0…...

vscode配置C/C++环境(保姆级详细教程)

一. 引言 VSCode&#xff0c;全称为Visual Studio Code&#xff0c;是一款由微软开发的免费、开源的轻量级代码编辑器&#xff0c;它支持多种编程语言和平台&#xff0c;并提供丰富的扩展功能&#xff0c;让开发者能够更高效地编写代码。 大家能来搜用如何在VSCode配置C/C环境…...

MDK keil STM32 局部变量不能查看值,显示为not in scope

用MDK调试程序&#xff0c;查看变量时watch窗口总是和 一、方法1&#xff1a;优化级别改为Level 0 1 编译器把这个局部变量给优化掉了&#xff0c;并没有在内存中生成&#xff0c;把优化级别改为Level 0&#xff0c;重新编译。 Keil默认优化是等级3&#xff0c;最高优化&…...

表连接查询之两个left join与递归SQL

一、如下SQL1 SELECT i.*,su1.name as createName,su2.name as updateNameFROM information ileft join sys_user su1 on su1.idi.create_idleft join sys_user su2 on su2.idi.update_id 二、分析 1、SELECT i.*,su.name as createName,sua.name as updateName FROM informati…...

2024.9.10

打的模拟赛难度很大,T1就2200分? 其中转化成差分数组上的问题很巧妙 还用了将数分成2的多次方的形式,这种套路在最近的几场比赛和题中都见到过,值得归纳一下 T3是长链剖分和对顶堆维护,太难写了还没写出来 T4仍然是概率题,但是并没有见过类似的出题方式,其中关键是:最大独…...

22_图论中的高级数据结构

菜鸟&#xff1a;老鸟&#xff0c;我最近在处理一个网络节点数据的问题&#xff0c;发现代码运行得特别慢。你能帮我看看有什么优化的方法吗&#xff1f; 老鸟&#xff1a;当然可以。你处理的是图结构对吗&#xff1f;你是如何存储和操作这些节点的&#xff1f; 菜鸟&#xf…...

axure判断

在auxre中我们也可以实现判断的功能&#xff0c;当目标等于什么内容时则执行下方的功能。 一、判断输入框中是否有值 画布添加一个输入框、一个文本标签删除其中内容&#xff0c;添加一个按钮&#xff0c;输入框命名为【文本显示】文本标签命名为【提示】 给按钮新增一个交互…...

【开源大模型生态7】华为的盘古大模型

鹏程盘古模型是全球首个全开源2000亿参数的自回归中文预训练语言大模型&#xff0c;在知识问答、知识检索、知识推理、阅读理解等文本生成领域表现突出。 2070亿参数&#xff0c;64层。 这里注意几个概念。 参数&#xff08;Parameters&#xff09;&#xff1a; 参数是指构成模…...

SprinBoot+Vue远程教育网站的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…...

docker的基本操作

目录 一&#xff0c;应用部署 创建容器 进入容器 创建有端口的容器 通过ssh进入容器 二、镜像操作 搜索镜像 拉取镜像 查看本地镜像 删除镜像 导入镜像 三、容器操作 创建并启动容器 使用 docker run 命令创建并启动一个容器 创建一个有端口号的容器 查看正在运…...

理解 RabbitMQ:生产者、连接、通道、交换机、队列与消费者的消息流

在分布式消息系统中&#xff0c;RabbitMQ 是一个非常流行的消息代理。它的核心理念是解耦应用程序的生产者和消费者&#xff0c;使得消息能够可靠地从一方传递到另一方。本文将带你深入了解 RabbitMQ 中 生产者、连接、通道、交换机、队列 和 消费者 之间的消息流&#xff0c;并…...

【截图服务 +打包】pkg打包 puppeteer

目录 最后结论 windows打包成服务 定制executablePath 服务遇到的问题 使用java开一个线程启动 遇到的问题与解决 版本匹配问题 打出包后的运行报错问题 linux下的安装 安装n 库缺少 程序运行后的报错 制作 运行报错与修改后成功 参考文档 最后结论 pkg -t win…...

深入理解Servlet的并发处理机制小波制图流程图

在Java Web开发中&#xff0c;Servlet是处理HTTP请求的核心组件。理解Servlet如何处理并发请求对于开发高性能Web应用至关重要。本文将深入探讨Servlet的生命周期、实例化过程以及多线程处理机制。 Servlet的生命周期和实例化 Servlet遵循单例模式&#xff0c;对于每个Servle…...

Ajax和XMLHttpRequest之间的关系

Ajax和XMLHttpRequest之间的关系是非常密切的。Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种网页开发技术&#xff0c;用于创建交互式的应用程序或网站。而XMLHttpRequest是Ajax的核心技术之一。 XMLHttpRequest&#xff1a;这是一个JavaScript对象&…...

Linxu系统:kill命令

1、命令详解&#xff1a; kill命令是用于向进程发送信号&#xff0c;通常用来终止某个指定PID服务进程&#xff0c;kill命令可以发送不同的信号给目标进程&#xff0c;来实现不同的操作&#xff0c;如果不指定信号&#xff0c;默认会发送 TERM 信号&#xff08;15&#xff09;&…...

解决缺少genconfig

编译鸿蒙L0系统时&#xff0c;遇到报错&#xff1a; [OHOS INFO] Returned 127. [OHOS INFO] stderr: [OHOS INFO] [OHOS INFO] env: “genconfig”: 没有那个文件或目录 [OHOS INFO] [OHOS INFO] See //kernel/liteos_m/BUILD.gn:34:1: whence it was imported. [OHOS INFO] …...

百易云资产管理运营系统 house.save.php SQL注入漏洞

1 产品简介 百易云资产管理运营系统&#xff0c;是专门针对企业不动产资产管理和运营需求而设计的一套综合解决方案。该系统能够覆盖资产的全生命周期管理&#xff0c;包括资产的登记、盘点、评估、处置等多个环节&#xff0c;同时提供强大的运营分析功能&#xff0c;帮助企业…...

【安卓13 源码】Input子系统(3) - EventHub增加设备的流程

由前面的分析知道&#xff0c;在创建inputreader 线程的时候&#xff0c;会去循环执行 looponce 方法。主要的处理工作是&#xff1a; 通过 getEvents() 从 EventHub 获取未处理的事件&#xff0c;这些事件分为两类&#xff1a;一类是原始输入事 件即从设备节点中读取出的原始…...

基于JAVA+SpringBoot+Vue的网上商城系统的设计与实现

基于JAVASpringBootVue的网上商城系统的设计与实现 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1…...

Mysql基础练习题 1729.求关注者的数量 (力扣)

编写解决方案&#xff0c;对于每一个用户&#xff0c;返回该用户的关注者数量。 #按 user_id 的顺序返回结果表 题目链接&#xff1a; https://leetcode.cn/problems/find-followers-count/description/ 建表插入语句&#xff1a; Create table If Not Exists Followers(us…...

【鸿蒙HarmonyOS NEXT】页面和自定义组件生命周期

【鸿蒙HarmonyOS NEXT】页面和自定义组件生命周期 一、环境说明二、页面和自定义组件生命周期三、示例代码加以说明四、小结 一、环境说明 DevEco Studio 版本&#xff1a; API版本&#xff1a;以12为主 二、页面和自定义组件生命周期 需要明确几个概念&#xff1a; 页面…...

Node.js Express 框架

Node.js Express 框架 介绍 Express 是一个快速、开放、极简的 Node.js Web 框架。它为构建 Web 应用程序和服务提供了一个强大的工具集,使得开发过程更加高效和便捷。Express 的设计哲学是提供一个最小的 API,让开发者可以轻松地构建自定义的 Web 应用程序。它被广泛用于构…...

生日贺卡录放音芯片,多段音频录音ic生产厂商,NVF04M-32minute

可以录音播放的生日贺卡与传统的纸质贺卡相比&#xff0c;它有着创意以及个性的特点&#xff0c;仅需少量的电子元器件&#xff0c;即可实现录音功能&#xff0c;搭配上文字&#xff0c;让声音存储在生日贺卡里&#xff0c;让贺卡也变得有温度&#xff0c;祝福我想亲口对TA说。…...

电影《西施新传》首映礼,九月金秋全国正式公映

2024年9月1日&#xff0c;古装谋略情感影片《西施新传》在无锡大世界影城中山路IMAX激光店举办首映礼。电影《西施新传》根据作家沈雅琴、笔名一蝶的同名小说改编&#xff0c;以家喻户晓四大美人之首的西施为主人公&#xff0c;讲述了春秋末期吴越战争的故事。越国败于吴国&…...