【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
的信号readyRead
和stateChanged
到对应的槽函数receiveMessage
和mStateChanged
。
-
2. 处理“连接服务端”按钮点击事件
-
步骤
调用
QTcpSocket
的connectToHost()
方法来连接服务器。 -
关键代码段:
void Widget::on_btn_start_clicked() { // 尝试连接到指定的IP地址和端口号 tcp_socket->connectToHost(QHostAddress(IP), PORT); }
-
详细说明:
-
tcp_socket->connectToHost(QHostAddress(IP), PORT)
: 连接到指定的IP地址和端口号。此函数异步执行,连接成功或失败将触发相应的信号。
-
3. 处理“断开服务端”按钮点击事件
-
步骤
调用
QTcpSocket
的disconnectFromHost()
方法断开与服务器的连接。 -
关键代码段:
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:父对象指针,默认为nullptr
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();
// 槽函数:处理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;
}
}