【Qt】TCP客户端

目录

效果

步骤

[1 创建项目](#1 创建项目)

[2 创建界面](#2 创建界面)

[3 实现功能](#3 实现功能)


效果

步骤

1 创建项目

创建项目,这里使用Qt Widgets Application模板,项目名称这里设置为"TCPClient"

使用qmake构建工具

这里类名命名为"Widget_TCP"

这里构建套件使用MinGW

2 创建界面

创建UI界面如下图所示

使用到的qss代码:

javascript 复制代码
/* ========== QWidget ========== */
QWidget {
    font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
    font-size: 13px;
    color: #2c3e50;
}

/* ========== QLabel ========== */
QLabel {
    color: #34495e;
    font-weight: 500;
    font-size: 13px;
    padding: 2px 0px;
}

QLabel#titleLabel {
    font-size: 18px;
    font-weight: 700;
    color: #2c3e50;
    padding: 8px 0px 12px 0px;
    letter-spacing: 1px;
}

/* ========== QLineEdit ========== */
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;
}

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 ========== */
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#cancelButton {
    background-color: #eef1f5;
    color: #4a5a6e;
}

QPushButton#cancelButton:hover {
    background-color: #e2e6ed;
    color: #2c3e50;
}

QPushButton#cancelButton:pressed {
    background-color: #d0d6df;
}

/* "连接"按钮 */
QPushButton#connectButton {
    background-color: #4a90d9;
    color: #ffffff;
}

QPushButton#connectButton:hover {
    background-color: #5b9ee6;
    box-shadow: 0 4px 12px rgba(74, 144, 217, 0.35);
}

QPushButton#connectButton:pressed {
    background-color: #3a7bc7;
    box-shadow: 0 2px 6px rgba(74, 144, 217, 0.25);
}

QPushButton#connectButton:disabled {
    background-color: #b0c4de;
    color: #e8edf5;
}

/* ========== QTextEdit ========== */
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 实现功能

在项目文件(.pro)中添加网络模块"network"

添加如下代码:

cpp 复制代码
#ifndef WIDGET_TCP_H
#define WIDGET_TCP_H

#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QDateTime>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget_TCP;
}
QT_END_NAMESPACE

class Widget_TCP : public QWidget
{
    Q_OBJECT

public:
    explicit Widget_TCP(QWidget *parent = nullptr);
    ~Widget_TCP() override;

private slots:
    //按钮槽函数
    void on_pushButton_cancel_clicked();
    void on_pushButton_connect_clicked();
    void on_pushButton_send_clicked();

    // TCP Socket 槽函数
    void onConnected();
    void onDisconnected();
    void onErrorOccurred(QAbstractSocket::SocketError error);
    void onReadyRead();

private:
    Ui::Widget_TCP *ui;

    QTcpSocket *socket;

    // 辅助函数
    void updateUIStatus(bool connected);
    void appendMessage(const QString &message);
    bool isConnected() const;
};
#endif // WIDGET_TCP_H
cpp 复制代码
#include "widget_tcp.h"
#include "ui_widget_tcp.h"

Widget_TCP::Widget_TCP(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget_TCP)
{
    ui->setupUi(this);


    setWindowTitle("TCP客户端");  // 设置窗口标题
    ui->pushButton_send->setEnabled(false);  // 默认禁用发送按钮

    socket = new QTcpSocket;  //创建socket对象

    // 连接信号槽
    connect(socket, &QTcpSocket::connected, this, &Widget_TCP::onConnected);
    connect(socket, &QTcpSocket::disconnected, this, &Widget_TCP::onDisconnected);
    connect(socket, &QTcpSocket::errorOccurred, this, &Widget_TCP::onErrorOccurred);
    connect(socket, &QTcpSocket::readyRead, this, &Widget_TCP::onReadyRead);
}

Widget_TCP::~Widget_TCP()
{
    delete ui;
}

// ========== 按钮槽函数 ==========
void Widget_TCP::on_pushButton_cancel_clicked()
{
    if (isConnected()) {
        socket->disconnectFromHost();
        appendMessage("用户主动断开连接");
    } else if (socket->state() == QAbstractSocket::ConnectingState) {
        socket->abort();
        appendMessage("已取消连接");
        updateUIStatus(false);
    } else {
        // 清空消息区域
        ui->textEdit_message->clear();
        appendMessage("已清空消息记录");
    }
}

void Widget_TCP::on_pushButton_connect_clicked()
{
    //获取ip地址和端口号
    QString IP = ui->lineEdit_address->text();
    QString port = ui->lineEdit_port->text();

    //连接服务器
    socket->connectToHost(QHostAddress(IP), port.toShort());
}


void Widget_TCP::on_pushButton_send_clicked()
{
    if (!isConnected()) {
        QMessageBox::warning(this, "未连接", "请先连接到服务器!");
        return;
    }

    QString message = ui->lineEdit_sendMessage->text().trimmed();
    if (message.isEmpty()) {
        QMessageBox::information(this, "提示", "请输入要发送的消息!");
        ui->lineEdit_sendMessage->setFocus();
        return;
    }

    // 发送消息
    QByteArray data = message.toUtf8();
    qint64 bytesWritten = socket->write(data);

    if (bytesWritten == -1) {
        appendMessage("❌ 发送失败: " + socket->errorString());
    } else {
        // 显示发送的消息(自己发的显示在右侧,用不同颜色)
        appendMessage("我: " + message);
        ui->lineEdit_sendMessage->clear();
        ui->lineEdit_sendMessage->setFocus();
    }
}

// ========== TCP Socket 槽函数 ==========
void Widget_TCP::onConnected()
{
    appendMessage("✅ 连接成功!");
    updateUIStatus(true);
    ui->lineEdit_sendMessage->setFocus();
    ui->pushButton_send->setEnabled(true);
}

void Widget_TCP::onDisconnected()
{
    appendMessage("⚠️ 连接已断开");
    updateUIStatus(false);
}

void Widget_TCP::onErrorOccurred(QAbstractSocket::SocketError error)
{
    QString errorMsg;
    switch (error) {
    case QAbstractSocket::ConnectionRefusedError:
        errorMsg = "连接被拒绝,请检查服务器是否启动";
        break;
    case QAbstractSocket::RemoteHostClosedError:
        errorMsg = "远程主机已关闭连接";
        break;
    case QAbstractSocket::HostNotFoundError:
        errorMsg = "主机地址未找到,请检查IP地址";
        break;
    case QAbstractSocket::SocketTimeoutError:
        errorMsg = "连接超时,请检查网络或服务器状态";
        break;
    default:
        errorMsg = QString("连接错误: %1").arg(socket->errorString());
        break;
    }

    appendMessage("❌ " + errorMsg);
    QMessageBox::critical(this, "连接错误", errorMsg);
    updateUIStatus(false);
}

void Widget_TCP::onReadyRead()
{
    // 读取服务器发送的数据
    QByteArray data = socket->readAll();
    QString message = QString::fromUtf8(data);

    // 显示接收到的消息(服务器发的显示在左侧,用蓝色)
    appendMessage("服务器: " + message);
}

// ========== 辅助函数 ==========
void Widget_TCP::updateUIStatus(bool connected)
{
    if (connected) {
        ui->textEdit_message->append("连接成功");
    } else {
        ui->textEdit_message->append("连接失败");
    }
}

void Widget_TCP::appendMessage(const QString &message)
{
    // 获取当前时间
    QString timeStr = QDateTime::currentDateTime().toString("hh:mm:ss");

    // 追加到文本编辑框
    ui->textEdit_message->append(QString("%1:%2").arg(timeStr).arg(message) );

    // 自动滚动到底部
    QTextCursor cursor = ui->textEdit_message->textCursor();
    cursor.movePosition(QTextCursor::End);
    ui->textEdit_message->setTextCursor(cursor);
}


bool Widget_TCP::isConnected() const
{
    return socket->state() == QAbstractSocket::ConnectedState;
}