目录
[1. 创建项目](#1. 创建项目)
[2. 创建界面](#2. 创建界面)
[3. 实现功能](#3. 实现功能)
[3.1 支持单客户端连接](#3.1 支持单客户端连接)
[3.2 支持多客户端连接](#3.2 支持多客户端连接)
效果

步骤
1. 创建项目
这里项目名称命名为"TCPServer"

构建系统使用qmake

类名这里命名为"Widget_TCPServer"


构建套件使用MinGW


2. 创建界面
创建如下界面

涉及到的样式代码如下:
css
QWidget {
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
font-size: 13px;
color: #2c3e50;
}
QWidget#Widget_TCP {
background-color: #ffffff;
border-radius: 12px;
border: 1px solid #e8ecf1;
}
QLabel {
color: #34495e;
font-weight: 500;
font-size: 13px;
padding: 2px 0px;
}
/* 标题标签("TCP服务端") */
QLabel#label {
font-size: 18px;
font-weight: 700;
color: #2c3e50;
padding: 8px 0px 12px 0px;
letter-spacing: 1px;
}
QLineEdit {
background-color: #f0f2f5;
border: 1.5px solid #dcdfe6;
border-radius: 8px;
padding: 8px 12px;
min-height: 20px;
color: #2c3e50;
selection-background-color: #4a90d9;
transition: border-color 0.2s;
margin-right: 14px;
}
QLineEdit:hover {
border-color: #a0c4f0;
background-color: #f8faff;
}
QLineEdit:focus {
border-color: #4a90d9;
background-color: #ffffff;
box-shadow: 0 0 0 3px rgba(74, 144, 217, 0.15);
}
QLineEdit:disabled {
background-color: #e9ecef;
color: #6c7a89;
border-color: #d5dbe3;
}
QPushButton {
border: none;
border-radius: 8px;
padding: 9px 28px;
font-weight: 600;
font-size: 13px;
min-width: 80px;
min-height: 30px;
transition: all 0.2s;
}
QPushButton#pushButton_connect {
background-color: #4a90d9;
color: #ffffff;
}
QPushButton#pushButton_connect:hover {
background-color: #5b9ee6;
box-shadow: 0 4px 12px rgba(74, 144, 217, 0.35);
}
QPushButton#pushButton_connect:pressed {
background-color: #3a7bc7;
box-shadow: 0 2px 6px rgba(74, 144, 217, 0.25);
}
QPushButton#pushButton_connect:disabled {
background-color: #b0c4de;
color: #e8edf5;
}
QTextEdit {
background-color: #fafbfc;
border: 1.5px solid #e4e7ed;
border-radius: 8px;
padding: 10px;
color: #2c3e50;
font-size: 13px;
line-height: 1.6;
selection-background-color: #4a90d9;
}
QTextEdit:focus {
border-color: #4a90d9;
background-color: #ffffff;
}
/* 滚动条美化 */
QTextEdit QScrollBar:vertical {
background: #f0f2f5;
width: 10px;
border-radius: 5px;
}
QTextEdit QScrollBar::handle:vertical {
background: #c0c8d6;
border-radius: 5px;
min-height: 30px;
}
QTextEdit QScrollBar::handle:vertical:hover {
background: #a0aab8;
}
QTextEdit QScrollBar::add-line:vertical,
QTextEdit QScrollBar::sub-line:vertical {
height: 0px;
}
3. 实现功能
3.1 支持单客户端连接
在项目文件(.pro)中添加网络模块"network"

代码如下:
cpp
#ifndef WIDGET_TCPSERVER_H
#define WIDGET_TCPSERVER_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget_TCPServer;
}
QT_END_NAMESPACE
class Widget_TCPServer : public QWidget
{
Q_OBJECT
public:
explicit Widget_TCPServer(QWidget *parent = nullptr);
~Widget_TCPServer() override;
private slots:
void on_pushButton_connect_clicked(); // 启动/停止按钮槽函数
void onNewConnection(); // 新客户端连接
void onReadyRead(); // 读取客户端数据
void onClientDisconnected(); // 客户端断开
void onServerError(QAbstractSocket::SocketError error);
private:
Ui::Widget_TCPServer *ui;
QTcpServer *tcpServer; // TCP服务器对象
QTcpSocket *clientSocket ; // 客户端socket
bool isListening = false;
void appendMessage(const QString &msg); // 在textEdit中追加消息
void updateClientList(); // 更新客户端列表
void startServer(); // 启动服务
void stopServer(); // 停止服务
};
#endif // WIDGET_TCPSERVER_H
cpp
#include "widget_tcpserver.h"
#include "ui_widget_tcpserver.h"
#include <QNetworkInterface>
#include <QMessageBox>
#include <QDebug>
#include <QDateTime>
Widget_TCPServer::Widget_TCPServer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget_TCPServer)
{
ui->setupUi(this);
tcpServer = new QTcpServer;
// 设置端口号默认值
ui->lineEdit_port->setText("8888");
// 禁用客户端列表的编辑功能(仅显示)
ui->listWidget_clients->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 创建TCP服务器
tcpServer = new QTcpServer(this);
connect(tcpServer, &QTcpServer::newConnection, this, &Widget_TCPServer::onNewConnection);
connect(tcpServer, &QTcpServer::acceptError, this, &Widget_TCPServer::onServerError);
}
Widget_TCPServer::~Widget_TCPServer()
{
delete ui;
if(tcpServer && tcpServer->isListening()) {
tcpServer->close();
}
if(clientSocket && clientSocket->state() == QAbstractSocket::ConnectedState) {
clientSocket->disconnectFromHost();
}
}
// 启动/停止按钮槽函数
void Widget_TCPServer::on_pushButton_connect_clicked()
{
if (!isListening) {
startServer();
} else {
stopServer();
}
}
// 启动服务
void Widget_TCPServer::startServer()
{
// 检查端口是否有效
bool ok;
quint16 port = ui->lineEdit_port->text().toUShort(&ok);
if (!ok || port == 0) {
QMessageBox::warning(this, "错误", "请输入有效的端口号 (1-65535)");
return;
}
QHostAddress address;
QString ipStr = ui->comboBox_IP->currentText();
if (ipStr == "0.0.0.0") {
address = QHostAddress::Any;
} else {
address = QHostAddress(ipStr);
if (address.isNull()) {
QMessageBox::warning(this, "错误", "无效的IP地址");
return;
}
}
// 尝试监听
if (!tcpServer->listen(address, port)) {
QMessageBox::critical(this, "启动失败",
QString("无法监听 %1:%2\n错误: %3")
.arg(ipStr).arg(port)
.arg(tcpServer->errorString()));
return;
}
isListening = true;
ui->pushButton_connect->setText("停止");
ui->comboBox_IP->setEnabled(false);
ui->lineEdit_port->setEnabled(false);
appendMessage(QString("服务已启动,监听 %1:%2").arg(ipStr).arg(port));
}
// 停止服务
void Widget_TCPServer::stopServer()
{
if (clientSocket) {
clientSocket->disconnectFromHost();
if (clientSocket->state() != QAbstractSocket::UnconnectedState) {
clientSocket->waitForDisconnected(3000);
}
clientSocket->deleteLater();
clientSocket = nullptr;
updateClientList();
}
if (tcpServer->isListening()) {
tcpServer->close();
}
isListening = false;
ui->pushButton_connect->setText("启动");
ui->comboBox_IP->setEnabled(true);
ui->lineEdit_port->setEnabled(true);
appendMessage("服务已停止");
}
// 新客户端连接
void Widget_TCPServer::onNewConnection()
{
// 接受新客户端
clientSocket = tcpServer->nextPendingConnection();
if (!clientSocket) return;
// 设置信号连接
connect(clientSocket, &QTcpSocket::readyRead, this, &Widget_TCPServer::onReadyRead);
connect(clientSocket, &QTcpSocket::disconnected, this, &Widget_TCPServer::onClientDisconnected);
//connect(clientSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &Widget_TCPServer::onServerError);
QString clientInfo = QString("%1:%2").arg(clientSocket->peerAddress().toString()).arg(clientSocket->peerPort());
appendMessage(QString("新客户端连接: %1").arg(clientInfo));
updateClientList();
}
// 读取客户端数据
void Widget_TCPServer::onReadyRead()
{
qDebug() << "onReadyRead entered";
if (!clientSocket)
{
qDebug() << "clientSocket is null";
return;
}
QByteArray data = clientSocket->readAll();
if (data.isEmpty()) return;
QString msg = QString::fromUtf8(data);
appendMessage(QString("收到客户端: %1").arg(msg));
}
// 客户端断开
void Widget_TCPServer::onClientDisconnected()
{
if (!clientSocket) return;
QString clientInfo = QString("%1:%2")
.arg(clientSocket->peerAddress().toString())
.arg(clientSocket->peerPort());
clientSocket->deleteLater();
clientSocket = nullptr;
appendMessage(QString("客户端已断开: %1").arg(clientInfo));
updateClientList();
}
// 服务器错误处理
void Widget_TCPServer::onServerError(QAbstractSocket::SocketError error)
{
Q_UNUSED(error);
appendMessage(QString("服务器错误: %1").arg(tcpServer->errorString()));
}
// 在消息显示区域追加文本
void Widget_TCPServer::appendMessage(const QString &msg)
{
ui->textEdit_message->append(QDateTime::currentDateTime().toString("[hh:mm:ss] ") + msg);
}
// 更新客户端列表(只显示当前连接)
void Widget_TCPServer::updateClientList()
{
ui->listWidget_clients->clear();
if (clientSocket && clientSocket->state() == QAbstractSocket::ConnectedState) {
QString info = QString("%1:%2")
.arg(clientSocket->peerAddress().toString())
.arg(clientSocket->peerPort());
ui->listWidget_clients->addItem(info);
} else {
ui->listWidget_clients->addItem("无客户端连接");
}
}
此时效果如下:

3.2 支持多客户端连接
代码如下:
cpp
#ifndef WIDGET_TCPSERVER_H
#define WIDGET_TCPSERVER_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QList>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget_TCPServer;
}
QT_END_NAMESPACE
class Widget_TCPServer : public QWidget
{
Q_OBJECT
public:
explicit Widget_TCPServer(QWidget *parent = nullptr);
~Widget_TCPServer() override;
private slots:
void on_pushButton_connect_clicked(); // 启动/停止按钮槽函数
void onNewConnection(); // 新客户端连接
void onReadyRead(); // 读取客户端数据
void onClientDisconnected(); // 客户端断开
void onServerError(QAbstractSocket::SocketError error);
private:
Ui::Widget_TCPServer *ui;
QTcpServer *tcpServer; // TCP服务器对象
QTcpSocket *clientSocket ; // 客户端socket
bool isListening = false;
QList<QTcpSocket*> m_clientSockets; // 存储所有客户端socket
void appendMessage(const QString &msg); // 在textEdit中追加消息
void updateClientList(); // 更新客户端列表
void startServer(); // 启动服务
void stopServer(); // 停止服务
};
#endif // WIDGET_TCPSERVER_H
cpp
#include "widget_tcpserver.h"
#include "ui_widget_tcpserver.h"
#include <QNetworkInterface>
#include <QMessageBox>
#include <QDebug>
#include <QDateTime>
Widget_TCPServer::Widget_TCPServer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget_TCPServer)
{
ui->setupUi(this);
tcpServer = new QTcpServer;
// 设置端口号默认值
ui->lineEdit_port->setText("8888");
// 禁用客户端列表的编辑功能(仅显示)
ui->listWidget_clients->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 创建TCP服务器
tcpServer = new QTcpServer(this);
connect(tcpServer, &QTcpServer::newConnection, this, &Widget_TCPServer::onNewConnection);
connect(tcpServer, &QTcpServer::acceptError, this, &Widget_TCPServer::onServerError);
}
Widget_TCPServer::~Widget_TCPServer()
{
delete ui;
if(tcpServer && tcpServer->isListening()) {
tcpServer->close();
}
if(clientSocket && clientSocket->state() == QAbstractSocket::ConnectedState) {
clientSocket->disconnectFromHost();
}
}
// 启动/停止按钮槽函数
void Widget_TCPServer::on_pushButton_connect_clicked()
{
startServer();
}
// 启动服务
void Widget_TCPServer::startServer()
{
QString ip = ui->comboBox_IP->currentText();
QHostAddress address;
if (!address.setAddress(ip)) {
address = QHostAddress::Any;
}
quint16 port = ui->lineEdit_port->text().toUShort();
if (!tcpServer->listen(address, port)) {
appendMessage("启动失败: " + tcpServer->errorString());
return;
}
ui->pushButton_connect->setText("停止");
appendMessage(QString("服务已启动,监听 %1:%2").arg(address.toString()).arg(port));
// 清空之前可能的残留客户端
qDeleteAll(m_clientSockets);
m_clientSockets.clear();
updateClientList();
}
// 停止服务
void Widget_TCPServer::stopServer()
{
tcpServer->close();
// 断开所有客户端
for (QTcpSocket *socket : m_clientSockets) {
socket->disconnectFromHost();
socket->deleteLater();
}
m_clientSockets.clear();
ui->pushButton_connect->setText("启动");
appendMessage("服务已停止");
updateClientList();
}
// 新客户端连接
void Widget_TCPServer::onNewConnection()
{
while (tcpServer->hasPendingConnections()) {
QTcpSocket *client = tcpServer->nextPendingConnection();
m_clientSockets.append(client);
connect(client, &QTcpSocket::readyRead, this, &Widget_TCPServer::onReadyRead);
connect(client, &QTcpSocket::disconnected, this, &Widget_TCPServer::onClientDisconnected);
QString peer = QString("%1:%2").arg(client->peerAddress().toString()).arg(client->peerPort());
appendMessage("新客户端连接: " + peer);
updateClientList();
}
}
// 读取客户端数据
void Widget_TCPServer::onReadyRead()
{
QTcpSocket *client = qobject_cast<QTcpSocket*>(sender());
if (!client) return;
QByteArray data = client->readAll();
QString msg = QString::fromUtf8(data).trimmed();
QString peer = QString("%1:%2").arg(client->peerAddress().toString()).arg(client->peerPort());
appendMessage(QString("来自 %1: %2").arg(peer).arg(msg));
// 回显给该客户端
// client->write(data);
// 广播给所有客户端
// for (QTcpSocket *sock : m_clientSockets) {
// sock->write(data);
// }
}
// 客户端断开
void Widget_TCPServer::onClientDisconnected()
{
QTcpSocket *client = qobject_cast<QTcpSocket*>(sender());
if (!client) return;
QString peer = QString("%1:%2").arg(client->peerAddress().toString()).arg(client->peerPort());
appendMessage("客户端断开: " + peer);
m_clientSockets.removeAll(client);
client->deleteLater(); // 安全删除
updateClientList();
}
// 服务器错误处理
void Widget_TCPServer::onServerError(QAbstractSocket::SocketError error)
{
Q_UNUSED(error);
appendMessage(QString("服务器错误: %1").arg(tcpServer->errorString()));
}
// 在消息显示区域追加文本
void Widget_TCPServer::appendMessage(const QString &msg)
{
ui->textEdit_message->append(QDateTime::currentDateTime().toString("[hh:mm:ss] ") + msg);
}
// 更新客户端列表
void Widget_TCPServer::updateClientList()
{
ui->listWidget_clients->clear();
for (QTcpSocket *client : m_clientSockets) {
QString info = QString("%1:%2")
.arg(client->peerAddress().toString())
.arg(client->peerPort());
ui->listWidget_clients->addItem(info);
}
}
此时效果如下
