嵌入式养成计划-46----QT--简易版网络聊天室实现

一百一十九、简易版网络聊天室实现

119.1 QT实现连接TCP协议

119.1.1 基于TCP的通信流程

在这里插入图片描述
在这里插入图片描述

119.1.2 QT中实现服务器过程

  1. 使用QTcpServer实例化一个服务器对象
  2. 设置监听状态,通过listen()函数,可以监听特定的主机,也可以监听所有客户端,端口号可以是系统自动分配的,也可以是指定端口号。
  3. 如果有客户端发来连接请求,那么服务器就自动发射一个newConnection信号,我们就可以将该信号连接到自定义的槽函数中处理该客户端的操作。
  4. 此时服务器和客户端已经建起了连接,可以调用nextPandingConnection获取最新连接的客户端套接字,可以将该套接字存放在服务器的客户端容器中。
  5. 当客户端发来数据时,该客户端就会自动发射一个readyRead信号,我们可以将该信号连接到自定义的槽函数中读取客户端数据。
  6. 通过read(),readLine(),readAll()读取套接字里的数据,可以通过write()往套接字中写入数据
  7. 关闭服务器使用close即可

119.1.3 QT中实现客户端过程

  1. 使用QTcpSocket实例化一个客户端对象
  2. 将客户端连接到服务器,使用connectToHost, 给定主机地址,端口号
  3. 如果连接成功,该客户端会自动发射connected信号,我们可以将该信号连接到自定义的槽函数中处理相关逻辑代码。
  4. 此时,客户端和服务器已经建立了连接,如果服务端发来数据,那么该客户端会自定发射readyRead信号,可以将该信号连接到自定义的槽函数中读取服务端中数据
  5. 可以使用read() readLine() readAll()读取套接字中数据,使用write往套接字中写入数据
  6. 客户端断开与服务器的连接,使用disConnectFromHost, 如果断开成功,客户端会自动发射disconnected信号,我们可以将该信号连接到自定义的槽函数中处理相关逻辑代码。

119.2 服务器端

119.2.1 UI 界面

在这里插入图片描述

119.2.2 qt_server.h

#ifndef QT_SERVER_H
#define QT_SERVER_H#include <QWidget>
#include <QTcpServer>
#include <QList>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Qt_Server; }
QT_END_NAMESPACEclass Qt_Server : public QWidget
{Q_OBJECTpublic:Qt_Server(QWidget *parent = nullptr);~Qt_Server();private slots:void on_startBtn_clicked();public slots://  自定义的 处理连接的槽函数声明void newConnection_slot();//  自定义的 处理接收数据的槽函数声明void readyRead_slot();private:Ui::Qt_Server *ui;QTcpServer *server;QList<QTcpSocket *> socketList;
};
#endif // QT_SERVER_H

119.2.3 qt_server.cpp

#include "qt_server.h"
#include "ui_qt_server.h"Qt_Server::Qt_Server(QWidget *parent): QWidget(parent), ui(new Ui::Qt_Server)
{ui->setupUi(this);//  给服务器指针创建空间server = new QTcpServer(this);
//    socketList = new QList<>();
}Qt_Server::~Qt_Server()
{delete ui;
}//  点击启动服务器按钮对应的槽函数实现
void Qt_Server::on_startBtn_clicked()
{if(ui->startBtn->text() == "启动服务器"){//  获取UI界面上输入的端口号quint16 port = ui->portEdit->text().toUInt();//  使服务器进入监听状态,返回值是bool类型if(server->listen(QHostAddress::Any,port)){QMessageBox::information(this,"提示","服务器启动成功");}else{QMessageBox::critical(this,"错误","服务器启动失败");}//  此时服务器已经进入监听状态,如果有客户端发来链接请求,//  则服务器会自动发射一个newConnection信号,需要将该信号连接到自定义的槽函数中处理连接的套接字connect(server, &QTcpServer::newConnection, this, &Qt_Server::newConnection_slot);ui->startBtn->setText("已启动服务器");ui->startBtn->setStyleSheet("background-color:green");}else{server->close();disconnect(server, &QTcpServer::newConnection, this, &Qt_Server::newConnection_slot);ui->startBtn->setStyleSheet("background-color:white");ui->startBtn->setText("启动服务器");}}//  自定义的 处理连接的槽函数声明
void Qt_Server::newConnection_slot()
{qDebug() << "有新客户的连接";//  获取最新连接的客户端套接字,并放入容器中,此时客户端与服务器已经建立起连接QTcpSocket *s = server->nextPendingConnection();socketList.push_back(s);//  如果有客户端发送数据,那么此客户端就会自动发射readyRead信号//  需要将该信号与自定义的处理接收数据的槽函数连接connect(s, &QTcpSocket::readyRead, this, &Qt_Server::readyRead_slot);
}//  自定义的 处理接收数据的槽函数实现
void Qt_Server::readyRead_slot()
{//  移除无效的客户端//  遍历所有的客户端for(int i=0; i<socketList.count(); i++){//  判断每个客户端的状态,返回值是枚举类型//  socketList.at(i)->state();if(0 == socketList.at(i)->state()){//  移除当前客户端,通过下标删除socketList.removeAt(i);}}//  遍历容器,找到有需要读取数据的客户端for(int i=0; i<socketList.count(); i++){//  如果当前客户端的 有效字节数 不为0,代表当前客户端有需要读取的数据if(0 != socketList.at(i)->bytesAvailable()){//  读取客户端中的数据QByteArray msg = socketList.at(i)->readAll();//  将读取的数据放到UI界面上ui->listWidget->addItem(QString::fromLocal8Bit(msg));//  将数据发送给所有客户端for (int j=0; j<socketList.count(); j++) {socketList.at(i)->write(msg);}}}
}

119.2.4 main.cpp

#include "qt_server.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Qt_Server w;w.show();return a.exec();
}

119.3 客户端

119.3.1 UI 界面

在这里插入图片描述

119.3.2 qt_client.h

#ifndef QT_CLIENT_H
#define QT_CLIENT_H#include <QWidget>
#include <QTcpServer>
#include <QList>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Qt_Client; }
QT_END_NAMESPACEclass Qt_Client : public QWidget
{Q_OBJECTpublic:Qt_Client(QWidget *parent = nullptr);~Qt_Client();public slots:void connected_slot();void readyRead_slot();private slots:void on_connectBtn_clicked();void on_msgBtn_clicked();void on_disconnectBtn_clicked();private:Ui::Qt_Client *ui;//  定一个客户端对象QTcpSocket *socket;//  定义一个用户名变量QString uname;
};
#endif // QT_CLIENT_H

119.3.3 qt_client.cpp

#include "qt_client.h"
#include "ui_qt_client.h"Qt_Client::Qt_Client(QWidget *parent): QWidget(parent), ui(new Ui::Qt_Client)
{ui->setupUi(this);//  给客户端对象创建空间socket = new QTcpSocket(this);//  初始化UI界面的组件状态ui->msgEdit->setEnabled(false);ui->msgBtn->setEnabled(false);ui->disconnectBtn->setEnabled(false);}Qt_Client::~Qt_Client()
{delete ui;
}void Qt_Client::connected_slot()
{//  告诉服务器我进来了QString msg = uname + " 来了,快接驾";//  将这个消息发送给服务器socket->write(msg.toLocal8Bit());//  此时说明服务器与客户端已经建立连接//  现在将UI界面的组件状态修改一下ui->msgEdit->setEnabled(true);ui->msgBtn->setEnabled(true);ui->disconnectBtn->setEnabled(true);ui->unameEdit->setEnabled(false);ui->ipEdit->setEnabled(false);ui->portEdit->setEnabled(false);ui->connectBtn->setEnabled(false);//  如果服务器发来数据,客户端会自动发射readyRead信号//  因此需要将readyRead信号连接到自定义的槽函数//  因为只需要连接一次,所以也是该在构造函数中写连接函数connect(socket, &QTcpSocket::readyRead, this, &Qt_Client::readyRead_slot);
}void Qt_Client::readyRead_slot()
{//  走到了这一步,说明服务器给客户端发送了消息,现在需要进行读取QByteArray msg = socket->readAll();//  将这个数据放到UI界面的消息显示框中ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}//  连接服务器按钮 对应的槽函数
void Qt_Client::on_connectBtn_clicked()
{//  获取UI界面的IP和PORT,还有unameQString ip = ui->ipEdit->text();quint16 port = ui->portEdit->text().toUInt();uname = ui->unameEdit->text();//  使客户端连接服务器socket->connectToHost(ip, port);//  判断客户端是否成功连接服务器,成功则客户端会自动发射connected信号//  将该信号连接到自定义的槽函数中//  因为只需要连接一次,所以连接函数应该写在构造函数中connect(socket, &QTcpSocket::connected, this, &Qt_Client::connected_slot);
}void Qt_Client::on_msgBtn_clicked()
{//  获取UI界面上输入的内容QString msg = uname + " : " + ui->msgEdit->toPlainText();//  将消息发送给服务器socket->write(msg.toLocal8Bit());}void Qt_Client::on_disconnectBtn_clicked()
{QString msg = uname + " 走咯,我还会再回来的";//  将消息发送给服务器socket->write(msg.toLocal8Bit());//  断开链接socket->close();disconnect(socket, &QTcpSocket::readyRead, this, &Qt_Client::readyRead_slot);disconnect(socket, &QTcpSocket::connected, this, &Qt_Client::connected_slot);//  更改UI界面的组件状态ui->msgEdit->setEnabled(false);ui->msgBtn->setEnabled(false);ui->disconnectBtn->setEnabled(false);ui->unameEdit->setEnabled(true);ui->ipEdit->setEnabled(true);ui->portEdit->setEnabled(true);ui->connectBtn->setEnabled(true);
}

119.3.4 main.cpp

#include "qt_client.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Qt_Client w;w.show();return a.exec();
}

119.3.1 UI 界面

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

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

相关文章

Cannot load from short array because “sun.awt.FontConfiguration.head“ is null

错误描述 在使用Easyexcel时发生了报错&#xff0c;请求返回空白 但是只在Linux上出现了该报错&#xff0c;在本地windows环境没有出现 JDK都使用的是17版本 错误原因 由于在linux上缺失Easyexcel使用的字体导致 解决办法 下载一个jdk1.8 在其jre/lib目录里复制fontconfi…

VTK8.0.0编译+QT5.9.2+VS2017

背景 VTK网上资料较多并且使用较多的版本可能是VTK8.2.0&#xff0c;但是由于之前先配置了QT 5.9.2 msvc2017 PCL1.8.1 VTK8.0.0环境&#xff0c;听说有人PCL1.8.1配置VTK8.2.0实测版本不兼容&#xff0c;需修改源码调试&#xff0c;比较麻烦&#xff0c;所以之前就使用的VT…

Ultralytics YOLOv8的关键特点

计算机视觉领域正在迅速增长&#xff0c;其中最重要的技术之一是目标检测。每六个月都会出现新的目标检测算法&#xff0c;不断提高准确性&#xff0c;与之前的算法相比。Ultralytics YOLOv8是最先进的目标检测算法&#xff0c;不仅提供卓越的准确性&#xff0c;还支持CPU和GPU…

微信小程序连接数据库与WXS的使用

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《微信小程序开发实战》。&#x1f3af;&#x1f3a…

google登录k8s dashboard ui显示“您的连接不是私密连接”问题解决梳理

1.问题描述 OS Version:CentOS Linux release 7.9.2009 (Core) K8S Version:Kubernetes v1.20.4 k8s dashboard ui安装完毕后&#xff0c;通过google浏览器登录返现https网页&#xff0c;发现非官方的https网页无法打开 网址&#xff1a;https://192.168.10.236:31001 2.原…

C++之struct匿名结构体实例(二百四十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

互联网Java工程师面试题·Java 面试篇·第二弹

目录 15、什么是不可变对象&#xff08;immutable object&#xff09;&#xff1f;Java 中怎么创建一个不可变对象&#xff1f; 16、我们能创建一个包含可变对象的不可变对象吗&#xff1f; 17、Java 中应该使用什么数据类型来代表价格&#xff1f; 18、怎么将 byte 转换为 Str…

TCP和UDP的原理及其区别(三次握手、四次挥手)

TCP和UDP都是在传输层上工作的协议&#xff0c;用于在网络中传输数据。 1、TCP和UDP之间的区别 TCP和UDP的主要区别在于它们提供的服务和特性。TCP提供可靠的、有序的、基于连接的数据传输&#xff0c;适用于对数据完整性和可靠性要求较高的应用&#xff08;邮件、短信&#xf…

常见面试题-Redis专栏(二)

theme: cyanosis typora-copy-images-to: imgsRedisson 分布式锁&#xff1f;在项目中哪里使用&#xff1f;多久会进行释放&#xff1f;如何加强一个分布式锁&#xff1f; 答&#xff1a; 首先入门级别的分布式锁是通过 setnx 进行实现&#xff0c;使用 setnx 实现有四个注意…

学生学徒作品分享——金融大模型-房屋租金价格影响因素分析与预测

金融大模型-房屋租金价格影响因素分析与预测项目背景 广州作为中国最发达的城市之一&#xff0c;每年都吸引大量务工人员前来就业&#xff0c;而租房是他们需要解决的最大问题之一&#xff0c;各地区租房需求日益增长。在租房过程&#xff0c;价格、交通是重要的考虑因素&a…

LabVIEW中管理大型数据

LabVIEW中管理大数据 LabVIEW的最大优势之一是自动内存管理。这种内存管理允许用户轻松创建字符串、数组和集群&#xff0c;而无需C/C用户经常担心。但是&#xff0c;这种内存管理设计为绝对安全&#xff0c;因此数据被非常频繁地复制。这通常不会造成任何问题&#xff0c;但是…

Python--循环中的两大关键词 break 与 continue

在Python循环中&#xff0c;经常会遇到两个常见的关键词&#xff1a;break 与 continue break&#xff1a;代表终止整个循环结构 continue&#xff1a;代表中止当前本次循环&#xff0c;继续下一次循环 break&#xff1a; 英 /breɪk/ v. 打破&#xff0c;打碎&#xff0c…

asp.net企业招聘管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio计算机毕业设计

一、源码特点 asp.net 企业招聘管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语 言开发 asp.net企业招聘管理系统 二、功…

【LeetCode】94. 二叉树的中序遍历 [ 左子树 根结点 右子树 ]

题目链接 文章目录 Python3方法一&#xff1a; 递归 ⟮ O ( n ) ⟯ \lgroup O(n) \rgroup ⟮O(n)⟯方法二&#xff1a; 迭代 ⟮ O ( n ) ⟯ \lgroup O(n) \rgroup ⟮O(n)⟯方法三&#xff1a; Morris ⟮ O ( n ) 、 O ( 1 ) ⟯ \lgroup O(n)、O(1) \rgroup ⟮O(n)、O(1)⟯ C…

库的操作【MySQL】

文章目录 创建数据库字符集和校验规则概念分类例子 查看数据库显示创建语句修改数据库删除数据库备份和恢复备份恢复 创建数据库 SQL: CREATE DATABASE [IF NOT EXISTS] db_name [[DEFAULT] CHARSETcharset_name] [[DEFAULT] COLLATEcollation_name];其中&#xff0c;大写的单…

ubuntu 18.04 开机自启 打开终端执行脚本

一 打开设置开机自启配置程序 alt F2 输入 gnome-session-properties 或 终端输入 gnome-session-properties 二 添加开机自启配置 点右方的add加入 填写名称&#xff0c;可自定义 填写指令&#xff0c;即开机想要执行的指令 gnome-terminal -x bash -c “ls; exec bash” …

SpringBoot(二)集成 Quartz:2.5.4

Quartz是一个广泛使用的开源任务调度框架&#xff0c;用于在Java应用程序中执行定时任务和周期性任务。它提供了强大的调度功能&#xff0c;允许您计划、管理和执行各种任务&#xff0c;从简单的任务到复杂的任务。 以下是Quartz的一些关键特点和功能&#xff1a; 灵活的调度器…

Oracle的立场:官网更换首页与以色列站在一起

Oracle公司的官网&#xff0c;更换了首页内容&#xff0c;明确表明立场&#xff1a;Oracle与以色列站在一起。 声明指出&#xff1a; Oracle谴责针对以色列及其公民的恐怖袭击。Oracle将为其员工、以色列政府和国防机构提供一切必要的支持。 Magen David Adom是一家为以色列公民…

Android屏幕刷新机制

基础知识 CPU运行在Android设备上的中央处理器&#xff08;Central Processing Unit&#xff09;是Android设备的核心组件之一&#xff0c;负责执行计算和控制设备的各种操作。 Android设备上的CPU通常采用ARM架构&#xff0c;如ARM Cortex-A系列处理器。这些处理器具有高性能…

Hadoop3教程(三十三):(生产调优篇)慢磁盘监控与小文件归档

文章目录 &#xff08;161&#xff09;慢磁盘监控&#xff08;162&#xff09;小文件归档小文件过多的问题如何对小文件进行归档 参考文献 &#xff08;161&#xff09;慢磁盘监控 慢磁盘&#xff0c;是指写入数据时特别慢的一类磁盘。这种磁盘并不少见&#xff0c;当机器运行…