QTcpSocket
Qt的QTcpSocket
是用于实现TCP客户端或服务端通信的核心类,属于Qt Network
模块。它基于事件驱动的异步机制,通过信号和槽实现高效的非阻塞网络通信。
继承自QAbstractSocket
,提供以下核心功能:
- 建立/断开与TCP服务器的连接
- 异步发送和接收数据
- 错误检测与连接状态管理
- 信号槽机制驱动的事件处理
核心操作流程#
创建对象与基础配置#
Copy
| #include <QTcpSocket> |
| |
| |
| QTcpSocket *socket = new QTcpSocket(parent); |
| |
| |
| socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); |
连接服务器#
Copy
| |
| socket->connectToHost("127.0.0.1", 12345); |
发送数据#
Copy
| // 发送二进制数据 |
| QByteArray data = "Hello Server!"; |
| socket->write(data); |
| |
| // 发送文本(明确编码) |
| QString text = "你好,服务器!"; |
| socket->write(text.toUtf8()); // UTF-8 编码 |
接收数据#
Copy
| // 通过 readyRead 信号异步读取 |
| connect(socket, &QTcpSocket::readyRead, [=]() { |
| while (socket->bytesAvailable() > 0) { |
| QByteArray data = socket->readAll(); |
| qDebug() << "Received:" << data; |
| } |
| }); |
断开连接#
Copy
| |
| socket->disconnectFromHost(); |
| |
| |
| connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater); |
关键信号与状态管理#
信号 |
触发条件 |
connected() |
成功建立连接 |
disconnected() |
连接断开 |
readyRead() |
有数据可读 |
errorOccurred(QAbstractSocket::SocketError) |
发生错误 |
stateChanged(QAbstractSocket::SocketState) |
连接状态变化 |
完整示例#
客户端#
完整代码:
Github:Qt网络编程客户端代码
部分代码:
Copy
| 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网络编程服务端代码
部分代码:
Copy
| 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; |
| } |
| |
| 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); }); |
| |
| 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..."); |
| } |
| |
| } |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)