一、实验效果演示
实现 Qt 的 TCP 客户端,实现和服务器通信
二、代码框架

三、代码
tcpclient客户端代码
tcpclient.cpp
#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QDebug>
#include <QMessageBox>
#include <QRegExpValidator>
// 构造函数:初始化TCP客户端界面和成员变量
tcpclient::tcpclient(QWidget *parent)
: QWidget(parent) // 调用父类QWidget的构造函数
, ui(new Ui::tcpclient) // 初始化UI对象
, mSocket(nullptr) // 初始化TCP套接字指针为nullptr
{
ui->setupUi(this); // 初始化UI界面
setWindowTitle("TCP Client"); // 设置窗口标题为"TCP Client"
// 初始状态下禁用发送功能(未连接服务器时不能发送数据)
ui->lineEdit_send->setEnabled(false); // 禁用发送内容输入框
ui->pushButton_send->setEnabled(false); // 禁用发送按钮
// 设置IP地址验证器,确保输入的IP地址格式正确
// 创建正则表达式验证器,用于验证IPv4地址格式
QRegExpValidator *ipValidator = new QRegExpValidator(
// 正则表达式:匹配xxx.xxx.xxx.xxx格式的IPv4地址,每个xxx为0-255
QRegExp("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"),
this // 父对象为当前窗口,确保内存自动管理
);
ui->lineEdit_ip->setValidator(ipValidator); // 为IP输入框设置验证器
ui->lineEdit_ip->setText("192.168.53.128"); // 设置默认IP地址
}
// 析构函数:释放资源
tcpclient::~tcpclient()
{
// 如果套接字存在且处于连接状态,断开与服务器的连接
if (mSocket && mSocket->state() == QAbstractSocket::ConnectedState) {
mSocket->disconnectFromHost();
}
delete ui; // 释放UI对象
}
// "连接/断开"按钮点击事件处理函数
void tcpclient::on_pushButton_connect_clicked()
{
// 如果套接字未初始化,创建QTcpSocket对象
if (!mSocket) {
mSocket = new QTcpSocket(this); // 创建TCP套接字,父对象为当前窗口
// 连接信号与槽函数,处理各种网络事件
// 当连接成功建立时,触发onConnected函数
connect(mSocket, &QTcpSocket::connected, this, &tcpclient::onConnected);
// 当连接断开时,触发onDisconnected函数
connect(mSocket, &QTcpSocket::disconnected, this, &tcpclient::onDisconnected);
// 当有数据可读时,触发onReadyRead函数
connect(mSocket, &QTcpSocket::readyRead, this, &tcpclient::onReadyRead);
// 当发生错误时,触发onErrorOccurred函数(兼容旧版本Qt)
connect(mSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &tcpclient::onErrorOccurred);
}
// 检查当前连接状态
if (mSocket->state() == QAbstractSocket::ConnectedState) {
// 如果已连接,则断开连接
mSocket->disconnectFromHost();
} else {
// 未连接状态,尝试连接到服务器
QString ip = ui->lineEdit_ip->text(); // 获取输入的IP地址
quint16 port = ui->spinBox_port->value(); // 获取输入的端口号
// 检查IP地址是否为空
if (ip.isEmpty()) {
QMessageBox::warning(this, "警告", "请输入服务器IP地址"); // 弹出警告对话框
return; // 退出函数,不执行连接操作
}
// 连接到指定的IP地址和端口号
mSocket->connectToHost(QHostAddress(ip), port);
// 在消息显示区添加连接状态信息
ui->textBrowser->insertPlainText("正在连接到 " + ip + ":" + QString::number(port) + "...\n");
}
}
// "发送"按钮点击事件处理函数
void tcpclient::on_pushButton_send_clicked()
{
// 检查套接字是否存在且处于连接状态
if (!mSocket || mSocket->state() != QAbstractSocket::ConnectedState) {
return; // 不满足条件则退出函数
}
// 获取要发送的数据
QString str = ui->lineEdit_send->text();
// 检查输入内容是否为空
if (str.isEmpty()) {
return; // 内容为空则不发送
}
// 发送数据:将QString转换为UTF-8编码的字节数组
mSocket->write(str.toUtf8());
// 在界面上显示发送的内容,前缀"snd:"标识为发送的数据
ui->textBrowser->insertPlainText("snd: " + str + "\n");
// 清空发送输入框
ui->lineEdit_send->clear();
}
// 连接成功建立时的处理函数
void tcpclient::onConnected()
{
// 在消息显示区添加连接成功信息
ui->textBrowser->insertPlainText("已连接到服务器\n");
// 将"连接"按钮文本改为"断开连接"
ui->pushButton_connect->setText("断开连接");
// 启用发送功能(连接成功后才能发送数据)
ui->lineEdit_send->setEnabled(true); // 启用发送内容输入框
ui->pushButton_send->setEnabled(true); // 启用发送按钮
// 禁用IP和端口编辑(连接建立后不允许修改连接参数)
ui->lineEdit_ip->setEnabled(false); // 禁用IP输入框
ui->spinBox_port->setEnabled(false); // 禁用端口选择框
}
// 连接断开时的处理函数
void tcpclient::onDisconnected()
{
// 在消息显示区添加断开连接信息
ui->textBrowser->insertPlainText("已与服务器断开连接\n");
// 将"断开连接"按钮文本改回"连接"
ui->pushButton_connect->setText("连接");
// 禁用发送功能(断开连接后不能发送数据)
ui->lineEdit_send->setEnabled(false); // 禁用发送内容输入框
ui->pushButton_send->setEnabled(false); // 禁用发送按钮
// 启用IP和端口编辑(断开连接后允许修改连接参数)
ui->lineEdit_ip->setEnabled(true); // 启用IP输入框
ui->spinBox_port->setEnabled(true); // 启用端口选择框
}
// 有数据可读时的处理函数
void tcpclient::onReadyRead()
{
// 检查套接字是否存在
if (!mSocket) {
return; // 套接字不存在则退出
}
// 读取所有接收到的数据
QByteArray data = mSocket->readAll();
// 在界面上显示接收的内容,前缀"rcv:"标识为接收的数据
ui->textBrowser->insertPlainText("rcv: " + QString(data) + "\n");
}
// 网络错误发生时的处理函数
void tcpclient::onErrorOccurred(QAbstractSocket::SocketError error)
{
Q_UNUSED(error); // 标记error参数未使用,避免编译警告
// 检查套接字是否存在
if (mSocket) {
// 在消息显示区添加错误信息
ui->textBrowser->insertPlainText("错误: " + mSocket->errorString() + "\n");
}
}
tcpclient.h
#ifndef TCPCLIENT_H // 防止头文件被重复包含的宏定义
#define TCPCLIENT_H // 定义头文件宏
#include <QWidget> // 包含QWidget类,tcpclient类继承自QWidget
#include <QTcpSocket> // 包含QTcpSocket类,用于TCP通信
#include <QAbstractSocket> // 包含QAbstractSocket类,提供套接字的基本功能和枚举
#include <QRegExpValidator> // 包含QRegExpValidator类,用于正则表达式验证
#include <QMessageBox> // 包含QMessageBox类,用于显示消息对话框
#include <QHostAddress> // 包含QHostAddress类,用于处理IP地址
QT_BEGIN_NAMESPACE // Qt命名空间开始
namespace Ui { class tcpclient; } // 声明Ui命名空间中的tcpclient类(由.ui文件生成)
QT_END_NAMESPACE // Qt命名空间结束
// 定义tcpclient类,继承自QWidget,用于实现TCP客户端功能
class tcpclient : public QWidget
{
Q_OBJECT // 启用Qt的元对象系统,支持信号和槽机制
public:
// 构造函数:创建tcpclient对象,parent为父窗口指针,默认为nullptr
tcpclient(QWidget *parent = nullptr);
// 析构函数:释放tcpclient对象占用的资源
~tcpclient();
private slots: // 私有槽函数,用于处理各种事件
// 处理"连接/断开"按钮的点击事件
void on_pushButton_connect_clicked();
// 处理"发送"按钮的点击事件
void on_pushButton_send_clicked();
// 处理连接成功建立的事件
void onConnected();
// 处理连接断开的事件
void onDisconnected();
// 处理有数据可读的事件
void onReadyRead();
// 处理网络错误发生的事件,参数为错误类型
void onErrorOccurred(QAbstractSocket::SocketError error);
private: // 私有成员变量
Ui::tcpclient *ui; // 指向UI界面对象的指针,用于访问界面控件
QTcpSocket *mSocket; // 指向QTcpSocket对象的指针,用于TCP通信
};
#endif // TCPCLIENT_H // 结束头文件宏定义
tcpclient.pro
QT += core gui
QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
tcpclient.cpp
HEADERS += \
tcpclient.h
FORMS += \
tcpclient.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
main.cpp
#include "tcpclient.h" // 包含tcpclient类的头文件,用于创建客户端窗口对象
#include <QApplication> // 包含QApplication类的头文件,Qt应用程序的核心类
// 程序入口函数,argc是命令行参数数量,argv是命令行参数数组
int main(int argc, char *argv[])
{
// 创建QApplication对象a,初始化Qt应用程序,处理命令行参数
QApplication a(argc, argv);
// 创建tcpclient类的实例w,这是客户端的主窗口对象
tcpclient w;
// 显示主窗口w,此时窗口才会在屏幕上可见
w.show();
// 进入Qt应用程序的事件循环,等待用户交互(如点击按钮、输入文本等)
// 函数返回应用程序退出时的状态码
return a.exec();
}
tcpclient.ui(8个组件)
-
QT设计师界面UI 设计建议:
客户端 UI 应包含以下元素:
- IP 地址输入框(lineEdit_ip)
- 端口号选择框(spinBox_port)
- 连接 / 断开按钮(pushButton_connect)
- 发送内容输入框(lineEdit_send)
- 发送按钮(pushButton_send)
- 消息显示区域(textBrowser)

6TcpServer服务器端
tcpsever.cpp
#include "tcpserver.h"
#include "ui_tcpserver.h"
#include <QDebug>
TcpServer::TcpServer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::TcpServer)
{
ui->setupUi(this);
}
TcpServer::~TcpServer()
{
delete ui;
}
void TcpServer::on_pushButton_start_clicked()
{
//1.构建QTcpServer对象
mServer = new QTcpServer(this);
//连接有客户端连接上来的信号
QObject::connect(mServer,&QTcpServer::newConnection,this,[&](){
//获取客户端连接上来的套接字
mSocket = mServer->nextPendingConnection();
//获取客户端的地址
QHostAddress addr = mSocket->peerAddress();
qDebug()<<addr.toString()<<"连接上来!";
//使能发送
ui->lineEdit->setEnabled(true);
ui->pushButton_send->setEnabled(true);
//连接readyRead信号和槽
QObject::connect(mSocket,&QTcpSocket::readyRead,this,[&](){
//接收数据
QByteArray arr = mSocket->readAll();
//转换成字符串并显示
QString str(arr);
//显示
ui->textBrowser->insertPlainText("rcv:"+str+"\n");
});
});
//2.监听
mServer->listen(QHostAddress::Any,ui->spinBox->value());
//禁止修改
ui->spinBox->setEnabled(false);
ui->pushButton_start->setEnabled(false);
}
//发送
void TcpServer::on_pushButton_send_clicked()
{
//获取发送的数据
QString str = ui->lineEdit->text();
//转换成QByteArray
QByteArray arr;
arr.append(str);
//发送
mSocket->write(arr);
//显示要发送的内容
ui->textBrowser->insertPlainText("snd:"+str+"\n");
//清空
ui->lineEdit->clear();
}
main.cpp
#include "tcpserver.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TcpServer w;
w.show();
return a.exec();
}
tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <QWidget>
#include <QtNetwork>
QT_BEGIN_NAMESPACE
namespace Ui { class TcpServer; }
QT_END_NAMESPACE
class TcpServer : public QWidget
{
Q_OBJECT
public:
TcpServer(QWidget *parent = nullptr);
~TcpServer();
private slots:
void on_pushButton_start_clicked();
void on_pushButton_send_clicked();
private:
Ui::TcpServer *ui;
//TCP服务器
QTcpServer *mServer;
QTcpSocket *mSocket;
};
#endif // TCPSERVER_H
6TcpServer.pro
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
tcpserver.cpp
HEADERS += \
tcpserver.h
FORMS += \
tcpserver.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
tcpserver.ui(6个组件)
