首页
文章
留言
首页
文章
留言
Qt实现TCP通讯
2016 年 11 月 19 日
桌面应用
程序开发
C++
Qt
GUI
Qt 是一个跨平台 C++ 图形用户界面应用程序开发框架。它既可以开发 GUI 程序,也可用于开发非 GUI 程序,比如控制台工具和服务器。最近总结了下使用 Qt 来实现了 TCP 通讯,编写了一个客户端和服务器基于窗口通信的小程序。 #### 使用前配置 使用 Qt 网络功能需要在 `.pro` 文件增加网络库: ``` QT += network ``` #### 服务端 ##### 1、服务端用到了 QTcpSocket、QTcpSever 类。主要用到了6个步骤: (1)创建 QTcpSever 对象。 ```cpp server = new QTcpServer(); ``` (2)侦听一个端口,使得客户端可以使用这个端口访问服务端。 ```cpp server->listen(QHostAddress::Any, port) ``` (3)当服务端被客户端访问时,会发出 newConnection() 信号,因此为该信号添加槽函数,并用一个 QTcpSocket 对象接受客户端访问。 ```cpp connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect); void MainWindow::server_New_Connect() { // 获取客户端连接 socket = server->nextPendingConnection(); } ``` (4)使用 `socket` 的 `write` 函数向客户端发送数据。 ```cpp socket->write(data); ``` (5)当 `socket` 接收缓冲区有新数据到来时,会发出 `readRead()` 信号,因此为该信号添加槽函数以读取数据。 ```cpp QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); void MainWindow::socket_Read_Data() { QByteArray buffer; // 读取缓冲区数据 buffer = socket->readAll(); } ``` (6)取消侦听。 ```cpp server->close(); ``` ##### 2、以下是服务器的源码文件 首先是 mainwindow.h 文件: ```cpp // mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include
#include
#include
namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_pushButton_Listen_clicked(); void on_pushButton_Send_clicked(); void server_New_Connect(); void socket_Read_Data(); void socket_Disconnected(); private: Ui::MainWindow *ui; QTcpServer* server; QTcpSocket* socket; }; #endif // MAINWINDOW_H ``` 然后是 mainwindow.cpp 文件: ```cpp #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->lineEdit_Port->setText("8765"); ui->pushButton_Send->setEnabled(false); server = new QTcpServer(); // 连接信号槽 connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect); } MainWindow::~MainWindow() { server->close(); server->deleteLater(); delete ui; } void MainWindow::on_pushButton_Listen_clicked() { if(ui->pushButton_Listen->text() == tr("侦听")) { // 从输入框获取端口号 int port = ui->lineEdit_Port->text().toInt(); // 监听指定的端口 if(!server->listen(QHostAddress::Any, port)) { // 若出错,则输出错误信息 qDebug()<
errorString(); return; } // 修改按键文字 ui->pushButton_Listen->setText("取消侦听"); qDebug()<< "Listen succeessfully!"; } else { // 如果正在连接(点击侦听后立即取消侦听,若socket没有指定对象会有异常,应修正——2017.9.30) if(socket->state() == QAbstractSocket::ConnectedState) { // 关闭连接 socket->disconnectFromHost(); } // 取消侦听 server->close(); // 修改按键文字 ui->pushButton_Listen->setText("侦听"); // 发送按键失能 ui->pushButton_Send->setEnabled(false); } } void MainWindow::on_pushButton_Send_clicked() { qDebug() << "Send: " << ui->textEdit_Send->toPlainText(); // 获取文本框内容并以ASCII码形式发送 socket->write(ui->textEdit_Send->toPlainText().toLatin1()); socket->flush(); } void MainWindow::server_New_Connect() { // 获取客户端连接 socket = server->nextPendingConnection(); // 连接QTcpSocket的信号槽,以读取新数据 QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected); // 发送按键使能 ui->pushButton_Send->setEnabled(true); qDebug() << "A Client connect!"; } void MainWindow::socket_Read_Data() { QByteArray buffer; // 读取缓冲区数据 buffer = socket->readAll(); if(!buffer.isEmpty()) { QString str = ui->textEdit_Recv->toPlainText(); str+=tr(buffer); // 刷新显示 ui->textEdit_Recv->setText(str); } } void MainWindow::socket_Disconnected() { // 发送按键失能 ui->pushButton_Send->setEnabled(false); qDebug() << "Disconnected!"; } ``` #### 客户端 ##### 1、客户端的代码比服务端稍简单,使用QT中的QTcpSocket类与服务端进行通信只需要以下5步: (1)创建 QTcpSocket 套接字对象。 ```cpp socket = new QTcpSocket(); ``` (2)使用这个对象连接服务端。 ```cpp socket->connectToHost(IP, port); ``` (3)使用write函数向服务端发送数据。 ```cpp socket->write(data); ``` (4)当 `socket` 接收缓冲区有新数据到来时,会发出 `readRead()` 信号,因此为该信号添加槽函数以读取数据。 ```cpp QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); void MainWindow::socket_Read_Data() { QByteArray buffer; // 读取缓冲区数据 buffer = socket->readAll(); } ``` (5)断开与服务端的连接。(关于close()和disconnectFromHost()的区别,可以按F1看帮助) ```cpp socket->disconnectFromHost(); ``` ##### 2、以下是客户端的源码文件 首先是mainwindow.h文件: ```cpp // mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include
#include
namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_pushButton_Connect_clicked(); void on_pushButton_Send_clicked(); void socket_Read_Data(); void socket_Disconnected(); private: Ui::MainWindow *ui; QTcpSocket *socket; }; #endif // MAINWINDOW_H ``` 然后是 mainwindow.cpp 文件: ```cpp // mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); socket = new QTcpSocket(); // 连接信号槽 QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected); ui->pushButton_Send->setEnabled(false); ui->lineEdit_IP->setText("127.0.0.1"); ui->lineEdit_Port->setText("8765"); } MainWindow::~MainWindow() { delete this->socket; delete ui; } void MainWindow::on_pushButton_Connect_clicked() { if(ui->pushButton_Connect->text() == tr("连接")) { QString IP; int port; // 获取IP地址 IP = ui->lineEdit_IP->text(); // 获取端口号 port = ui->lineEdit_Port->text().toInt(); // 取消已有的连接 socket->abort(); // 连接服务器 socket->connectToHost(IP, port); // 等待连接成功 if(!socket->waitForConnected(30000)) { qDebug() << "Connection failed!"; return; } qDebug() << "Connect successfully!"; // 发送按键使能 ui->pushButton_Send->setEnabled(true); // 修改按键文字 ui->pushButton_Connect->setText("断开连接"); } else { // 断开连接 socket->disconnectFromHost(); // 修改按键文字 ui->pushButton_Connect->setText("连接"); ui->pushButton_Send->setEnabled(false); } } void MainWindow::on_pushButton_Send_clicked() { qDebug() << "Send: " << ui->textEdit_Send->toPlainText(); // 获取文本框内容并以ASCII码形式发送 socket->write(ui->textEdit_Send->toPlainText().toLatin1()); socket->flush(); } void MainWindow::socket_Read_Data() { QByteArray buffer; // 读取缓冲区数据 buffer = socket->readAll(); if(!buffer.isEmpty()) { QString str = ui->textEdit_Recv->toPlainText(); str+=tr(buffer); // 刷新显示 ui->textEdit_Recv->setText(str); } } void MainWindow::socket_Disconnected() { // 发送按键失能 ui->pushButton_Send->setEnabled(false); // 修改按键文字 ui->pushButton_Connect->setText("连接"); qDebug() << "Disconnected!"; } ```
0
相关文章
C/C++基础知识总结
Git使用总结
macOS常用命令
全部分类
前端
后端
运维
架构
算法
数据库
移动应用
桌面应用
程序开发
热门标签
Android
JavaScript
MongoDB
Qt
Nginx
Objective-C
Kubernetes
Lua
C++
Docker
iOS
MySQL
Linux
Kafka
GUI
Composer
NoSQL
Elasticsearch
HTML
Python
爬虫
OpenResty
Redis
CentOS
Sphinx
PHP
Shell
CSS
macOS
Supervisor
多线程
Git
热门文章
Kubernetes介绍
macOS常用命令
Elasticsearch详解
Qt实现TCP通讯
PHP开发之字符串处理
PHP开发之PDO使用总结
iOS开发之定时执行任务
10种常见的软件架构模式
OpenResty+Lua+Kafka收集日志
jquery.tmpl使用总结