当前位置: 首页 > news >正文

《操作系统实践-基于Linux应用与内核编程》第10章--实验 Qt聊天程序

 前言:

内容参考《操作系统实践-基于Linux应用与内核编程》一书的示例代码和教材内容,所做的读书笔记。本文记录再这里按照书中示例做一遍代码编程实践加深对操作系统的理解。

引用:

《操作系统实践-基于Linux应用与内核编程》

作者:房胜、李旭健、黄玲、李哲

出版社:清华大学出版社

资源:

 教材资源

链接: https://caiyun.139.com/m/i?1A5Ch36dl1whD  提取码:jdQe

课件和电子资料源码

链接: https://caiyun.139.com/m/i?1A5CvEKY07Uzs  提取码:xyv0

参考链接:

Qt 之网络编程_qt网络编程-CSDN博客

[QT_047]Qt学习之表单布局器(QFormLayout)-CSDN博客

Qt中采用多线程实现Socket编程_parent is qnativesocketenhine parrnt's thread is t-CSDN博客

正文

1. 登录窗口源码

参考电子资源中的源码 '' ch10/QChat/qdlglog.in.cpp",完善Qt聊天程序登录页面的源码。

在Qt Creator 点击 qdlglogin.cpp ,进入编辑页面,参考源码示例增加需要引入的头文件

#include "qdlglogin.h"
#include "ui_qdlglogin.h"//Add by dimon 2024/-0316 14:32, Copy the source code
#include "qdlggchat.h"
#include "common.h"
#include <QMessageBox> //弹出对话框
#include <QHostAddress>

此时发现 Qt Creator 提示错误,说找不到 'QHostAddress'头文件。原因是我们的Qt 项目需要用到 Qt 网络模块,而当前我们还没有引入 Qt 网络模块。

解决方案,参考链接博文,在项目 ".pro"文件中加入一行,在Qt项目中引起 Qt Network 模块,这样Qt Creator 就能找到 "QHostAddress"头文件了。

QT += network

Qt 之网络编程_qt网络编程-CSDN博客文章浏览阅读2.7w次,点赞21次,收藏38次。Qt Network模块提供的类允许编写 TCP/IP clients 和 servers。_qt网络编程https://blog.csdn.net/liang19890820/article/details/52249509

修改 qdlglogin.h 头文件,需要用到 Qt "QTcpSocket" 类,在qdlglogin.h文件头加上对 QtcpSocket的包含。Qt Creator只有在包含对应的头文件后,在Qt Crateor编辑器里才能智能提示补全头文件里的函数,类。

#ifndef QDLGLOGIN_H
#define QDLGLOGIN_H#include <QDialog>
#include <QTcpSocket> //QTcpSocket头文件

在 qdlglogin.h 中类 class qdlglogin 中加上 private 私有成员,登录页面中需要记录的用户ID,密码,服务器IP,服务器端口号,以及 *tcpSocket指针。

修改 qdlglogin.cpp的类构造函数,在构造qdlglogin登录对话框时,设置‘用户名’和‘密码’文本输入框的'LineEdit'的提示符,和密码输入文本对话框'LineEdit’的回显模式为 'LineEdit::Password'对密码做特殊回显。设置登录对话框的“登录”和“注册”按钮"QPushButton'初始化为非Enable模式,灰化不可以点击。

效果如下图

2. Qt布局器的使用

在设置qdlgchar.ui窗体的布局是,使用到了Qt Creator设计师界面的 Qt 布局器,Qt布局器可以使用的有水平布局,和垂直布局。

[QT_047]Qt学习之表单布局器(QFormLayout)-CSDN博客文章浏览阅读3.8k次,点赞2次,收藏17次。Qt学习之表单布局器(QFormLayout)_qformlayouthttps://blog.csdn.net/kongcheng253/article/details/128781000

Qt 布局器的使用技巧是:

1. 第一种方法,直接拖动Qt设计师界面到布局器到ui设计界面,然后拖动需要的widget组件到布局器。实际操作拖动之后,就会发现使用鼠标拖动窗体小组件widget到布局器的方式分非常容易误操作,总是不能选择到想要的小组件,或者小组件在布局器里自动排序出错等。

2. 第二种方法,是参考如上链接中的方法,先一次选中多个需要布局的窗体小组件,点击Qt ui设计菜单上的“打破布局”,破坏原有的布局;然后点击窗体菜单“水平布局”或者“垂直布局”,所选中的多个小组件就会自动加入到Qt布局器中。

注意:小组件被加入到布局器中之后,小组件的大小就不能调整了。如果想要再次调整小组件的大小,可以先选择小组件所在的父布局器 点击“破坏布局”,去掉布局之后就可以单独调整小组件的大小。调整小组件大小到之后,再把组件加入到Qt布局器。

点击右键“选择全部”会选择全部的窗体小组件, 然后点击“水平布局”,选择到的组件就都被加入到“水平布局器”中。

技巧1: 单击小组件的时候,总是会选择到Qt布局器里的一个小组件,有时间我们是想去选中整个Qt布局器。此时可以在ui设计界面右侧的窗体里用鼠标选择它的上一级布局器,就可以很容易的选择到父布局器。

技巧2:按下Ctrl键,鼠标单击右侧窗口中的布局器1,再单击布局器2,就会一次同时选择多个布局器。

3. 聊天窗口源码

参考源码实现 qdlggchar.cpp 的源码。需要设置的 comboBox , toolButton 等设置发送 txtEdit 组件中的字体的“字体”,“加粗”,“倾斜”,“颜色” 等 button关联的槽函数时,进入Ui设计界面,鼠标右键“转到槽”,实现槽函数(从示例代码中抄过来)。通过抄写示例代码的过程,实现了 qdlggchat.cpp 窗体的中按钮逻辑,也进一步接触和实践使用Qt来编程实现需要的功能。

4. 添加聊天服务器项目

新建项目,“QWidgetApplcation”,选择基类QDiaglog

使用Qt布局器,设计Qt聊天服务器的窗体布局。

参考电子资源中的示例源码,添加文件(类)qmydb.cpp(.h), qserver.cpp(.h), qthread.cpp(.h), quser.cpp(.h) 

右键单击"QChatServer"项目,"Add New",“Add C++ Class”,类命名为"qmydb",基类选贼为"QObject",确定,自动生成 qmydb.cpp 源文件和 qmydb.h头文件。

相同的操作,添加"qserver,quser, qthread, qserver” C++ 类的源文件和头文件。

注意: 如果Qt Creator 有多个项目打开,选择“添加到项目”是需要下拉框选择添加到指定的目标Qt项目。如果保持默认可能把文件会添加到不是自己想要的项目中。

4.1 服务器qmydb 数据库连接类

参考电子资源QChatServer源码中 qmydb 类,抄写源码到我们的Qt聊天服务器项目中。

添加头文件时,Qt Creator编辑器提示找不到"QSqlDatabase"头文件,原因项目用到了Qt数据库模块,但还没有把Qt数据库模块引入到我们QChatServer项目中。

如何查看,我们需要引入哪个Qt 数据库模块?

方式是查看Qt提供的帮助手册,在Qt帮助手册中会说明如果我们需要使用某个Qt模块,需要在项目中如何引入该模块。一般是在项目的 “.pro”文件中加上

Qt += xxx(模块名)

点击Qt Creator编辑器左侧菜单栏“帮助”,进入Qt 帮助文档,点击左下的过滤选择下拉框,下拉框里提供了“索引,查抄,书签,打开页面” 这4个选项。如果需要根据关键字搜索Qt 帮助文档,可以下拉框选择“查找”,输入关键字(例如 qsql),就会出现搜索结果,在搜索结果的帮助文档的起始部分,很明确的告诉我们如果书需要使用 Qt Sql模块需要包含头文件"QSqlDatabase",并且工程中需要在QMake中"QT += sql"引入sql模块(修改项目的 .pro文件,在文件结尾加上 QT += xxx)。


Header:
#include <QSqlDatabase> qmake:
QT += sql

我们QChatServer聊天服务器需要用到Qt Sql模块和Qt Network模块,所以在 QChatServer.pro 文件尾部加上如下的两行,就在我们的聊天服务器项目中引入了Qt sql和network项目。

4.2 服务器qtcpthread 处理tcp连接线程
4.3 服务器qserver类

对照着电子资源中的'c10/QChatServer'把源码,手动的敲到Virtualbox Ubuntu18.04 Qt5.14.2 编辑器之后,编译执行,进行联调 QChat 聊天程序。

在 QChatServer 聊天服务器假面,点击“启动服务” 按钮,聊天服务器开始监听来自聊天客户端的TCP连接,当收到聊天客户端的注册请求时, QChatServer 服务器端查询MySQL数据库,看用户是否已经注册,如果没有注册,就把用户插入到MySQL数据库并返回用户登录成功。

QChatServer 收到 QTcpSocket 连接请求时,新创建一个线程。并在线程里通过监听 socket 的 ' SIGNAL(readyRead()' 信号,并把槽函数‘SLOT(onReadyRead())’ 和这个信号函数'readyRead()'关联起来。当 QTcpSocket 有数据可以读取时,信号函数'readyRead()'被触发,发出信号,槽函数‘onReadyRead()’被执行。

槽函数'onReadyRead()'中连接数据库MySQL成功,并把用户注册名加入到 MySQL db_chat 数据库表 tb_chat 中。

QChatServer执行时,在窗口里打印出错误提示信息。

Current thread is:  QThread(0x56053b2b53f0)
tcpSocket wirte QByteArray to socket
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7fb3b8001b90), parent's thread is QTcpThread(0x56053b6114a0), current thread is QThread(0x56053b2b53f0)
 

百度搜索这个错误信息 ‘ Parent is QNativeSocketEngine(0x7fb3b8001b90), parent's thread is QTcpThread(0x56053b6114a0) ’,从如下链接的博文里解释了Qt 多线程编程里程序执行打印出该提示信息的原因。

Qt中采用多线程实现Socket编程_parent is qnativesocketenhine parrnt's thread is t-CSDN博客文章浏览阅读9.9k次,点赞5次,收藏14次。本文介绍的是Qt中采用多线程Socket编程,由于工作项目的需要,使用Qt的socket编程。Qt里的example是个不错的教程,但是当我把代码移植到多线程的环境时就出问题了:QObject: Cannot create children for a parent that is in a different thread.由于想要在线程中保留一个socket,以便维持双边通信,因此_parent is qnativesocketenhine parrnt's thread is tcprecv currenthttps://blog.csdn.net/ggggyj/article/details/51132225根据如下链接博客里的提示,我们修改QChatServer/qtcpthread.cpp 的程序源码中的信号-槽关联函数connect(),加上' Qt::DirectConnection '。QChatServer服务器再执行时,在新线程里就不会打印之前的错误提示 信息了。

    //connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);

4.4 服务器quser类

相关文章:

《操作系统实践-基于Linux应用与内核编程》第10章--实验 Qt聊天程序

前言: 内容参考《操作系统实践-基于Linux应用与内核编程》一书的示例代码和教材内容&#xff0c;所做的读书笔记。本文记录再这里按照书中示例做一遍代码编程实践加深对操作系统的理解。 引用: 《操作系统实践-基于Linux应用与内核编程》 作者&#xff1a;房胜、李旭健、黄…...

探究Kafka主题删除失败的根本原因

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 探究Kafka主题删除失败的根本原因 前言主题删除的基础主题删除的定义和作用&#xff1a;删除操作的基本流程&#xff1a; 可能存在删除异常的因素数据积压的处理方法Broker状态异常处理方法通用方法 前…...

JavaSE(上)-Day7

JavaSE&#xff08;上&#xff09;-Day7 类和对象封装privatethis构造方法标准JavaBean对象的内存图执行Test类main方法生成一个User对象的内存过程 基本数据类型和引用数据类型的区别this的内存原理成员变量和局部变量区别 类和对象 类是设计图纸&#xff0c;对象是真正的实例…...

记录一下在Pycharm中虚拟环境的创建

如果在Pycharm中要新建一个虚拟环境&#xff0c;那你可以在Terminal中选择Command Prompt&#xff0c;在这里面执行相关命令 一、安装了Anaconda&#xff0c;创建虚拟环境 当你使用解释器是Anaconda提供的时&#xff0c;你可以使用conda命令执行&#xff0c;见以下操作&#x…...

Python从入门到精通秘籍九

一、Python中文件编码概念 在Python中&#xff0c;文件编码指的是将文本内容转换为字节序列的过程。不同的编码方式使用不同的字符集和字节表示形式。下面是一个示例代码&#xff1a; # 写入文本到文件 text "你好&#xff0c;世界&#xff01;" with open("…...

善于利用window挂在全局变量

开发过程成中遇到一个奇怪的问题&#xff0c;打开一个echats图表之后&#xff0c;关闭echarts图再进入其他页面页面会报错提示 $&#xff08;...&#xff09;.draggble not a function经过一步步定位&#xff0c;发现echats图是通过后端获取js、css文件然后在本地绘制而成。而获…...

《C缺陷和陷阱》-笔记(5)

目录 一、整数溢出 溢出 如何防止溢出 二、为函数main提供返回值 连接 一、什么是连接器 连接器工作原理 三、声明与定义 四、命名冲突与static 修饰符 statia 一、整数溢出 溢出 C语言中存在两类整数算术运算&#xff0c;有符号运算与无符号运算。 在无…...

【数字图像处理matlab系列】保存图像

【数字图像处理系列】保存图像imwrite函数 使用函数imwrite可以将图像保存到本地上,该函数的语法为 imwrite(image_data, filename)其中,image_data是要写入的图像数据,可以是一个矩阵或一个三维数组(对于彩色图像),filename是要写入的文件名,可以包含路径信息。例如,…...

八股文三(Spring、Spring Cloud Alibaba)

Spring篇 什么是Spring Spring是个轻量级的框架&#xff0c;他有两大内核分别是IOC、AOPIOC是什么 * 依赖注入和控制反转&#xff0c;它是一种思想&#xff0c;创建对象不是直接new出来&#xff0c;而是交给IOC容器&#xff0c;由容器去创建进行管理&#xff0c;这就是控制反…...

一文带你详解天池工业数据集

人工智能是国家战略性新兴产业&#xff0c;制造业是国民经济的主体&#xff0c;随着人口红利的消失&#xff0c;加强设备自动化改造&#xff0c;提高生产自动化程度&#xff0c;减小劳动强度&#xff0c;改善作业环境&#xff0c;已经成为制造业的普遍共识。天池大赛开放出一批…...

08 龙芯平台openstack部署搭建-neutron-controller部署

一、创建neutron相关数据库、服务凭证和API端点 1.创建neutron数据库&#xff0c;授予合适的访问权限 mysql -uroot -ploongson -e “CREATE DATABASE neutron;” mysql -uroot -ploongson -e “GRANT ALL PRIVILEGES ON neutron.* TO ‘neutron’‘localhost’ IDENTIFIED B…...

JAVA 100道题(6)

6.创建一个表示矩形的类&#xff0c;包括宽度和高度属性&#xff0c;以及计算面积和周长的方法。 下面是一个简单的Python类&#xff0c;表示矩形&#xff0c;包含宽度和高度属性&#xff0c;以及计算面积和周长的方法&#xff1a; python复制代码 class Rectangle: def __ini…...

Leetcode面试经典150题

数组字符串 合并两个有序数组 思路 类似于归并排序&#xff0c;对两个有序数组进行合并即可&#xff0c;但是空间复杂度是O(nm); 代码 class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {int[] ans new int[n m];int i 0, j 0;int cnt 0;…...

王者荣耀使用的UDP通信,十几年编程没用过的协议

缘起 最近在查阅moba相关的资料时&#xff0c;看到了一篇王者荣耀的研发同学的技术分享&#xff0c;从文章中了解到王者荣耀的通信方式是UDP通信&#xff0c;回想到整个职业生涯&#xff0c;貌似并没有用过&#xff0c;今天特地整理下。 udp技术细节 udp协议 UDP协议叫做用…...

HiveQL详解

文章目录 前言一、数据定义语言&#xff08;DDL&#xff09;1. 数据库操作1.1 创建数据库1.2 删除数据库1.3 更改数据库1.4 使用数据库 2. 连接器操作2.1 创建连接器2.2 删除连接器2.3 修改连接器 3. 表操作3.1 创建表3.1.1 内部表与外部表3.1.1.1 内部表3.1.1.2 外部表3.1.1.3…...

Linux/Bizness

Enumeration nmap 用 nmap 扫描了常见的端口&#xff0c;发现对外开放了22,80,443 ┌──(kali㉿kali)-[~] └─$ nmap 10.10.11.252 Starting Nmap 7.93 ( https://nmap.org ) at 2024-03-08 01:21 EST Nmap scan report for 10.10.11.252 Host is up (0.36s latency). Not…...

mysql 数据库 增删改查 基本操作

目录 一 SQL 详细介绍 &#xff08;一&#xff09;SQL 分类 &#xff08;二&#xff09; SQL 语言规范 &#xff08;三&#xff09;数据库对象和命名 1&#xff0c;数据库的组件(对象)&#xff1a; 2&#xff0c;命名规则&#xff1a; &#xff08;四&#xff09; SQL…...

计算机网络——物理层(编码与调制)

计算机网络——编码与调制 基带信号和宽带信号编码与调制数字数据编码为数字信号非归零编码归零编码反向不归零编码曼彻斯特编码差分曼彻斯特编码4B/5B编码 数字数据调制为模拟信号模拟数据编码为数字信号模拟数据调制为模拟信号 我们之前讲了物理层的一些基础知识和两个准则&a…...

PHP魔术方法详解

__construct() 构造函数用于初始化新创建的对象。PHP 5 之后不推荐使用类名作为构造函数。 class Person {public $name;public $age;public function __construct($name, $age) {$this->name $name;$this->age $age;} }$person new Person("Alice", 30);…...

游戏 AI 反作弊|内附解决方案详情!

我们提出使用在游戏中广泛存在的回放日志数据&#xff0c;重构出玩家当局的表现。在回放 日志数据中&#xff0c;我们构建了玩家的时序行为数据&#xff0c;并基于该时序行为数据&#xff0c;分别搭建 了透视和自瞄外挂检测系统&#xff0c;该方法和系统可广泛应用于各种在线…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...