【QT】TCP

目录

核心API

示例:服务器和客户端信息互发

服务器代码实现

第一步:创建QTcpServer对象的实例

第二步:绑定信号槽,处理新的连接

第三步:绑定并监听端口号

客户端代码实现

第一步:创建socket对象的实例

第二步:和服务器建立连接

第三步:连接信号槽,处理响应 

第四步:等待连接结果,确认是否连接成功 

最终效果


UDP 无连接,不可靠传输,面向数据包,全双工

TCP 有连接,可靠传输,面向字节流,半双工

核心API

核心类是两个: QTcpServer QTcpSocket

QTcpServer ⽤于监听端⼝, 和获取客户端连接

名称
类型
说明
对标原⽣ API
listen(const QHostAddress&, quint16 port)
⽅法
绑定指定的地址和端⼝号, 并开始监听
bind 和 listen
nextPendingConnection()
⽅法
从系统中获取到⼀个已经建⽴好的 tcp 连接.
返回⼀个 QTcpSocket , 表⽰这个
客⼾端的连接.
通过这个 socket 对象完成和客⼾端 之间的通信
accept
newConnection
信号
有新的客⼾端建⽴连接好之后触发.
⽆ (但是类似于 IO 多路复⽤
中的通知机制)
QTcpSocket 用户客⼾端和服务器之间的数据交互
名称类型说明对标原⽣ API
readAll()
⽅法
读取当前接收缓冲区中的所有数据.
返回 QByteArray 对象.
read
write(const QByteArray& )
⽅法
把数据写⼊ socket 中.
write
deleteLater
⽅法
暂时把 socket 对象标记为⽆效. Qt
会在下个事件循环中析构释放该对
象.
⽆ (但是类似于 "半⾃动化的 垃圾回收")
readyRead
信号
有数据到达并准备就绪时触发
⽆ (但是类似于 IO 多路复⽤
中的通知机制)
disconnected
信号
连接断开时触发
⽆ (但是类似于 IO 多路复⽤
中的通知机制)

示例:服务器和客户端信息互发

服务器代码实现

首先区分QTcpServer 和 QTcpSocket,我们需要先使用QTcpServer来监听端⼝, 和获取客户端连接。

第一步:创建QTcpServer对象的实例

tcpServer = new QTcpServer(this代码);

第二步:绑定信号槽,处理新的连接

connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection);

processConnection方法 

void Widget::processConnection()

{

    //1.通过tcpserver拿到一个socket对象,通过这个对象来和客户端进行通信

    QTcpSocket* clientSocket = tcpServer->nextPendingConnection();

    QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端上线了!";

    ui->listWidget->addItem(log);

    //2.通过信号槽,来处理客户端发来请求的情况

    connect(clientSocket,&QTcpSocket::readyRead,this,[=](){

       // a) 读取请求数据,此处readAll返回的是QByteArray,通过赋值转成 QString

       QString request = clientSocket->readAll();

       // b) 根据请求处理响应

       const QString& response = process(request);

       // c) 把响应写回到客户端

       clientSocket->write(response.toUtf8());

       // d) 把上述信息记录到日志中

       QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "]" + "req:" + request + ",resp:" + response;

    });

       ui->listWidget->addItem(log);

    //3. 通过信号槽,来处理客户端断开连接的情况

    connect(clientSocket,&QTcpSocket::disconnected,this,[=](){

        //a) 把断开连接的信息通过日志显示出来

       QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端下线了!";

       ui->listWidget->addItem(log);

       //b) 手动释放clientSocket

       clientSocket->deleteLater();

    });

}

注意: 

  • 在Linux网络编程中,需要搞一个循环,循环的读取请求,循环的处理,在Qt中基于信号槽就不必循环了。每次客户端发来请求,都能触发readyRead信号。
  • 因为QTcpSocket是每个客户端都有一个这样的对象,存在n个,所以必须在客户端断开连接后手动释放,而QTcpServer和QUdpSocket只有一份
  • clientSocket->deleteLater();这个操作,不是立即销毁clientSocket,而是告诉Qt,下一轮事件循环时,再进行销毁操作。

第三步:绑定并监听端口号

    bool ret = tcpServer->listen(QHostAddress::Any,9090);

    if(!ret)

    {

        QMessageBox::critical(this,"服务器启动失败!",tcpServer->errorString());

        exit(1);

    }

完整代码:

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void processConnection();QString process(const QString request);
private:Ui::Widget *ui;QTcpServer* tcpServer;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QTcpSocket>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//修改窗口标题this->setWindowTitle("服务器");//2.创建QTcpServer的实例tcpServer = new QTcpServer(this);//3.通过信号槽,指定如何处理连接connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection);//4.绑定并监听端口号bool ret = tcpServer->listen(QHostAddress::Any,9090);if(!ret){QMessageBox::critical(this,"服务器启动失败!",tcpServer->errorString());exit(1);}
}Widget::~Widget()
{delete ui;
}void Widget::processConnection()
{//1.通过tcpserver拿到一个socket对象,通过这个对象来和客户端进行通信QTcpSocket* clientSocket = tcpServer->nextPendingConnection();QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端上线了!";ui->listWidget->addItem(log);//2.通过信号槽,来处理客户端发来请求的情况connect(clientSocket,&QTcpSocket::readyRead,this,[=](){// a) 读取请求数据,此处readAll返回的是QByteArray,通过赋值转成 QStringQString request = clientSocket->readAll();// b) 根据请求处理响应const QString& response = process(request);// c) 把响应写回到客户端clientSocket->write(response.toUtf8());// d) 把上述信息记录到日志中QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "]" + "req:" + request + ",resp:" + response;ui->listWidget->addItem(log);});//3. 通过信号槽,来处理客户端断开连接的情况connect(clientSocket,&QTcpSocket::disconnected,this,[=](){//a) 把断开连接的信息通过日志显示出来QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端下线了!";ui->listWidget->addItem(log);//b) 手动释放clientSocketclientSocket->deleteLater();});
}QString Widget::process(const QString request)
{return request;
}

客户端代码实现

客户端不需要跟服务器一样监听端口,因此只需要创建socket即可

第一步:创建socket对象的实例

 tcpSocket = new QTcpSocket(this);

第二步:和服务器建立连接

 这个函数不会阻塞等待三次握手完成的(非阻塞函数)

tcpSocket->connectToHost("127.0.0.1",9090);

第三步:连接信号槽,处理响应 

 connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){

       QString response = tcpSocket->readAll();

        ui->listWidget->addItem("服务器说:"+response);

    });

第四步:等待连接结果,确认是否连接成功 

    bool ret = tcpSocket->waitForConnected();

    if(!ret){

        QMessageBox::critical(this,"连接服务器",tcpSocket->errorString());

    }

完整代码: 

 widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTcpSocket* tcpSocket;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//1.设置窗口标题this->setWindowTitle("客户端");//2.创建socket对象的实例tcpSocket = new QTcpSocket(this);//3.和服务器建立连接  这个函数不会阻塞等待三次握手完成的(非阻塞函数)tcpSocket->connectToHost("127.0.0.1",9090);//4. 连接信号槽,处理响应connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){QString response = tcpSocket->readAll();ui->listWidget->addItem("服务器说:"+response);});//5.等待连接建立的结果,确认是否连接成功bool ret = tcpSocket->waitForConnected();if(!ret){QMessageBox::critical(this,"连接服务器",tcpSocket->errorString());}
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{//1.获取输入的内容const QString& text = ui->lineEdit->text();//2.发送数据给服务器tcpSocket->write(text.toUtf8());//3.把发送的信息显示到界面上ui->listWidget->addItem("客户端说:" + text);//4.清空输入框的内容ui->lineEdit->setText("");}

最终效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4.10 endpoint controller

EndpointSubset EndpointSubset 是一组具有公共端口集的地址&#xff0c;扩展的端点集是 Addresses (Pod IP 地址) 和 Ports (Service 名称和端口号) 的笛卡尔积。 下面是一个典型的 EndpointSubset 示例: Name: "test",Subsets: [{Addresses: [{"ip": …

financial是“财务”吗-《分析模式》漫谈14

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 “Analysis Patterns”的Preface&#xff08;前言&#xff09;有这么一句&#xff1a; David Creager, Steve Shepherd, and their team at Citibank worked with me in developing t…

鱼哥好书分享活动第27期:看完这篇《云原生安全》了解云原生环境安全攻防实战技巧!

鱼哥好书分享活动第27期&#xff1a;看完这篇《云原生安全》了解云原生安全攻防实战技巧&#xff01; 主要内容&#xff1a;读者对象&#xff1a;本书目录&#xff1a;了解更多&#xff1a;赠书抽奖规则: 当前全球数字化的发展逐步进入深水区&#xff0c;云计算模式已经广泛应用…

免费【2024】springboot 超市在线销售系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

【MATLAB源码-第238期】基于simulink的三输出单端反激flyback仿真,通过PWM和PID控制能够得到稳定电压。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 概述 反激变换器是一种广泛应用于电源管理的拓扑结构&#xff0c;特别是在需要隔离输入和输出的应用中。它的工作原理是利用变压器的储能和释放能量来实现电压转换和隔离。该图展示了一个通过脉宽调制&#xff08;PWM&#…

7.24 补题

C 小w和大W的决斗 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 小w和大W为了比出谁更聪明。决定进行一场游戏。游戏内容如下: 两人轮流操作&#xff0c;小w先进行操作&#xff0c;每次操作可以选择下列两个其一: 选择数组中的一…

唐老狮 UGUI 实战学习笔记

仅作学习&#xff0c;不做任何商业用途 不是源码&#xff0c;不是源码! 是我通过"照虎画猫"写的&#xff0c;可能有些小修改 不提供素材&#xff0c;所以应该不算是盗版资源&#xff0c;侵权删 using System.Collections; using System.Collections.Generic; using …

深度解析Linux-C——结构体(初始化,结构体数组,结构体大小,位段操作,联合体,内存对齐,C的预处理,宏和带参宏,条件编译)

目录 结构体的三种初始化 结构体的两种引用 结构体数组 结构体大小 结构体实现位段操作 联合体 内存对齐 C的预处理 带参宏 条件编译 结构体的三种初始化 定义如下结构体 struct student {char name[100]; int age; float height; } ; 1、定义变量时初始化 s…

Matrix Equation(高斯线性异或消元+bitset优化)

题目&#xff1a; 登录—专业IT笔试面试备考平台_牛客网 思路&#xff1a; 我们发现对于矩阵C可以一列一列求。 mod2&#xff0c;当这一行相乘1的个数为奇数时&#xff0c;z(i,j)为1&#xff0c;偶数为0&#xff0c;是异或消元。 对于b[i&#xff0c;j]*c[i,j],b[i,j]可以…

【MQTT(4)】开发一个客户端,QT-Android安卓手机版本,Mosquitto替换成libhv库

我们采用 libhv是一个类似于libevent、libev、libuv的跨平台网络库&#xff0c;提供了更易用的接口和更丰富的协议。 https://github.com/ithewei/libhv?tabreadme-ov-file 编译脚本如下 Android compile WITH_MQTT #https://developer.android.com/ndk/downloads #export…

tof系统标定流程步骤详解

1、tof标定概述 系统校准是一个减少ToF系统中系统误差影响的过程,如图1.1所示。本文件旨在介绍校准方法、设备和软件 1.1 系统误差 1.1.1 周期误差 谐波失真导致的相位(距离)相关误差。 1.1.2 固定相位模式噪声 由于解调信号的时延取决于可见像素位置以及VCSEL和传感器…

c++中的最长递增子序列(Longest Increasing Subsequence)(算法章完结)

前言 hello大家好啊&#xff0c;我是文宇。 今天是最后一篇算法&#xff08;暂时性的&#xff0c;以后可能还有&#xff09; 最长递增子序列&#xff08;Longest Increasing Subsequence&#xff09; 最长递增子序列&#xff08;Longest Increasing Subsequence&#xff0c…

【Golang 面试基础题】每日 5 题(十)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

【机器学习】解开反向传播算法的奥秘

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 解开反向传播算法的奥秘反向传播算法的概述反向传播算法的数学推导1. 前向传播2…

Linux进程——程序地址空间详解

文章目录 程序地址空间地址空间与物理内存什么是程序地址空间管理程序地址空间虚拟地址与物理地址的映射页表的结构及其作用程序地址空间的作用 程序地址空间 我们之前学习内存的时候&#xff0c;有说内存的分布大概是这样的 其中堆由下而上&#xff0c;栈由上而下 除此之外&…

JavaScript青少年简明教程:函数及其相关知识(下)

JavaScript青少年简明教程&#xff1a;函数及其相关知识&#xff08;下&#xff09; 继续上一节介绍函数相关知识。 箭头函数&#xff08;Arrow Function&#xff09; 箭头函数是 ES6&#xff08;ECMAScript 2015&#xff09;及更高版本中引入的语法&#xff0c;用于简化函数…

LeetCode:删除排序链表中的重复元素(C语言)

1、问题概述&#xff1a;给定一个已排序链表的头&#xff0c;删除重复元素&#xff0c;返回已排序的链表 2、示例 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2] 示例 2&#xff1a; 输入&#xff1a;head [1,1,2,3,3] 输出&#xff1a;[1,2,3] 3…

深度解析Memcached:内存分配算法的优化之旅

&#x1f525; 深度解析Memcached&#xff1a;内存分配算法的优化之旅 Memcached是一个高性能的分布式内存缓存系统&#xff0c;广泛用于提高Web应用程序的性能。它通过减少数据库查询次数来加速数据检索。然而&#xff0c;Memcached的性能在很大程度上取决于其内存分配算法的…

前端三方库零碎(持续更新)

本文主要记录开发实践过程中遇到的前端库&#xff0c;做个记录总结&#xff0c;以备不时之需 easyui-datagrid EasyUI 是一个基于 jQuery 的用户界面插件库&#xff0c;提供了丰富的用户界面组件和工具&#xff0c;其中包括 datagrid&#xff08;数据表格&#xff09;组件。E…

2024年国际高校数学建模大赛(IMMCHE)问题A:金字塔石的运输成品文章分享(仅供学习)

2024 International Mathematics Molding Contest for Higher Education Problem A: Transportation of Pyramid Stones&#xff08;2024年国际高校数学建模大赛&#xff08;IMMCHE&#xff09;问题A&#xff1a;金字塔石的运输&#xff09; 古埃及金字塔石材运输优化模型研究…