Qt 网络编程QTcpSocket客户端

QTcpSocket

Qt的QTcpSocket是用于实现TCP客户端或服务端通信的核心类,属于Qt Network模块。它基于事件驱动的异步机制,通过信号和槽实现高效的非阻塞网络通信。

继承自QAbstractSocket,提供以下核心功能:

  • 建立/断开与TCP服务器的连接
  • 异步发送和接收数据
  • 错误检测与连接状态管理
  • 信号槽机制驱动的事件处理

核心操作流程

创建对象与基础配置

#include <QTcpSocket>

// 创建 socket 对象
QTcpSocket *socket = new QTcpSocket(parent);

// 设置连接超时(可选)
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); // 禁用 Nagle 算法

连接服务器

// 异步连接(推荐)
socket->connectToHost("127.0.0.1", 12345);

发送数据

// 发送二进制数据
QByteArray data = "Hello Server!";
socket->write(data);

// 发送文本(明确编码)
QString text = "你好,服务器!";
socket->write(text.toUtf8()); // UTF-8 编码

接收数据

// 通过 readyRead 信号异步读取
connect(socket, &QTcpSocket::readyRead, [=]() {
    while (socket->bytesAvailable() > 0) {
        QByteArray data = socket->readAll();
        qDebug() << "Received:" << data;
    }
});

断开连接

// 主动断开
socket->disconnectFromHost();

// 断开后自动清理释放
connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);

关键信号与状态管理

信号 触发条件
connected() 成功建立连接
disconnected() 连接断开
readyRead() 有数据可读
errorOccurred(QAbstractSocket::SocketError) 发生错误
stateChanged(QAbstractSocket::SocketState) 连接状态变化

完整示例

客户端

完整代码:
Github:Qt网络编程客户端代码
部分代码:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->mainLayout);
    socket = new QTcpSocket(this);
    ui->pushButton_close->setDisabled(true);
    connect(socket, &QTcpSocket::connected, this, [=](){
        ui->textEdit_info->append("success connect to " + ip.toString() +", port: " + ui->lineEdit_port->text());
        QMessageBox::information(nullptr, "成功!", "连接成功");
    });
    connect(socket, &QTcpSocket::errorOccurred, [](QAbstractSocket::SocketError error) {
        QMessageBox::information(nullptr, "连接失败", "连接失败!");
        qDebug() << "连接失败:" << error;
    });
    connect(socket, &QTcpSocket::readyRead, this, [=](){
        QByteArray mes = socket->readAll();
        QString readData = QString::fromUtf8(mes);
        ui->textEdit_info->append("receive: " + readData);
    });
    // 已连接才启用断开按钮
    connect(socket, &QTcpSocket::stateChanged, this, [=](){
        if(socket->state() == QTcpSocket::ConnectedState)
            ui->pushButton_close->setDisabled(false);
        else
            ui->pushButton_close->setDisabled(true);
    });
}

Widget::~Widget()
{
    delete ui;
    if(socket->isValid()){
        socket->disconnect();
    }
}

void Widget::on_pushButton_send_clicked()
{
    mes = ui->lineEdit_messsage->text();
    if(socket->state() == QAbstractSocket::ConnectedState){
        socket->write(mes.toStdString().c_str());
        ui->textEdit_info->append("send: " + mes);
        ui->lineEdit_messsage->clear();
    }else{
        QMessageBox::warning(nullptr, "警告", "请先连接服务器");
    }
}


void Widget::on_pushButton_connect_clicked()
{
    ip = QHostAddress(ui->lineEdit_IpAddress->text());
    port = ui->lineEdit_port->text().toInt();
    if(socket->state() != QAbstractSocket::ConnectedState)
        socket->connectToHost(ip, port);


}


void Widget::on_pushButton_close_clicked()
{
    if(socket->state() == QTcpSocket::ConnectedState){
        socket->disconnectFromHost();
        ui->textEdit_info->append("Disconnect from " + ip.toString());
    }
}

服务端

完整代码:
Github:Qt网络编程服务端代码
部分代码:

void Widget::on_pushButton_listen_clicked()
{
    // 开始监听
    int port = ui->lineEdit_port->text().toInt();
    QHostAddress ip;
    if(ui->comboBox_ip->currentIndex() == 0)
        ip = QHostAddress::Any;
    else
        ip = QHostAddress(ui->comboBox->currentText());
    if(!server->listen(ip, port)){
        qDebug() << "listen Error!";
        return;
    }
    // qDebug() << "Server listening on port " + ui->lineEdit_port->text();
    ui->textEdit_info->append("Server listening on port " + ui->lineEdit_port->text());
    connect(server, &QTcpServer::newConnection, this, &Widget::handleNewConnection);

    ui->pushButton_listen->setDisabled(true);
    ui->pushButton_stop_listen->setDisabled(false);
}

void Widget::handleNewConnection()
{
    // 更新在线人数
    QString onlineNum = QString::fromStdString(
                std::to_string(server->findChildren<QTcpSocket*>().size()));
    ui->label_onlineNum->setText(onlineNum);
    QTcpSocket *currentClient = server->nextPendingConnection();
    clients.append(currentClient);
    ui->textEdit_info->append("new connection form :" + currentClient->localAddress().toString());
    // 读取客户端传来的数据
    connect(currentClient, &QTcpSocket::readyRead, [=](){ handleReadData(currentClient); });
    // 断开连接后 移除Socket释放内存
    connect(currentClient, &QTcpSocket::disconnected, [=](){ handleDisconnect(currentClient); });
}

void Widget::handleReadData(QTcpSocket* client)
{
    QByteArray data = client->readAll();
    QString utf8Text = QString::fromUtf8(data);
    ui->textEdit_info->append("receive: " + utf8Text);
    qDebug() << "message:" << utf8Text;
}


void Widget::on_pushButton_send_clicked()
{
    QString mes = ui->textEdit_sendData->toPlainText();
    // 广播发送给连接的所有客户端
    if(clients.size() == 0){
        QMessageBox::warning(nullptr, "无连接", "没有客户端连接到服务器");
        return;
    }
    for(auto client : clients){
        if(client->state() == QAbstractSocket::ConnectedState){
            client->write(mes.toStdString().c_str());
        }
    }
    ui->textEdit_info->append("send: " + mes);
    ui->textEdit_sendData->clear();

}


void Widget::on_pushButton_stop_listen_clicked()
{
    if(server->isListening()){
        // 断开连接槽函数
        disconnect(server, &QTcpServer::newConnection, this, &Widget::handleNewConnection);
        // 停止监听(停止接收新的连接)
        server->close();
        ui->pushButton_stop_listen->setDisabled(true);
        ui->pushButton_listen->setDisabled(false);

        // 强制断开所有已连接的客户端
        for (QTcpSocket *client : clients) {
            client->disconnectFromHost();
            client->deleteLater();
        }
        ui->textEdit_info->append("server closed...");
    }

}

posted @ 2025-02-20 11:22  风陵南  阅读(534)  评论(0)    收藏  举报