LanChatRoom局域网聊天室

news2025/2/22 16:09:48

CPP已经结课,我提交的项目是Qt的入门项目,局域网聊天室LanChatRoom。
image.png
这个代码重构了很多遍。第一遍是照着明哥推荐到书,把代码抄了一遍。
但抄下来之后,各种问题,而且是清朝老代码。抄了一遍之后,对代码的业务逻辑已经有了一个大体的了解。
整个开发周期持续了一周,其实最开始两天就已经能跑了。但我觉得远古代码太丑陋了,所以我扔掉了了书本,选择重写。
重写的过程也是曲折的,而且每次都遇到新的或旧的问题。这些问题以及解决方案将在接下来的内容中分享给大家。希望可以帮助到有需要的同学。

IDE的选择

如果是跟我一样的新手的话,第一遍建议是去找书,抄项目代码。当然是理解地抄,而不是单纯的Ctrl+CV。
IDE建议开始选择Qt自带的QtCreater。因为这涉及到对ui的操作,以及信号槽机制。这对没有qt经验的同学来说很不友好。
但是QtCreater太丑陋了,而且代码补全也不好用。
所以我当时是已经熟悉了ui的各项操作之后,就转到clion里了。
image.png
熟悉信号槽之后,就可以考虑转到clion了。
而且clion默认配置的cmakelist文件也更加清晰。
image.png
我一开始是去书栈网找Qt的教程,但它们很少用到ui文件,而是直接用代码控制元素。实际上很多对象的属性和方法,是不需要去记的,直接用designer编辑ui文件就可以。

消息广播

消息广播利用的是传输层协议UDP。
消息广播需要将消息发送给同一局域网内的所有设备。如果使用TCP协议,则需要在每个设备上都建立连接,这会增加网络开销。而UDP协议是无连接的协议,只需要设置源IP地址、源端口、目标IP地址和目标端口即可发送数据,因此可以提高传输效率。
UDP协议也存在一些缺点,例如数据传输不保证可靠性。在局域网聊天室中,如果某个设备没有接收到消息,则不会影响其他设备的正常使用。
image.png

文件传输

文件传输用的是传输层协议TCP。
TCP具有可靠性、有序性和流量控制等特性,可以保证文件传输的顺利进行。
而且文件的发送也利用了qt的信号槽机制。触发readyread或byteswritten信号之后,才传输下一部分文件。能够正常进入事件循环。这样不会堵塞当前线程,实现类似多线程的效果。
如果用循环的话,会卡在循环内,无法进入事件循环,在传输结束之前,显示“无响应”。
image.png
文件收发有很多共有的部分,比如界面元素、进度条更新。这些共有的部分可以单独封装,交给子类实现。这属于软件设计模式中的策略模式。
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);这是我每次重写都遇到的问题,需要指定代理方式,这可能跟我一直开着系统代理有关。

QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
connect(ui->selectFileButton, &QPushButton::clicked, this, &FileTransfer::selectFile);
connect(ui->transferFileButton, &QPushButton::clicked, this, &FileTransfer::transferFile);
connect(ui->cancelButton, &QPushButton::clicked, this, [=]() {
    this->close();
});

connect是qt特有的信号槽方法。使用的话需要继承QObject类,或者他的派生类。
selectFiletransferFile是纯虚函数,具体的策略在子类中实现。这里必须要用纯虚函数,交由子类实现。
cancelButton触发“取消”事件,通过lambda表达式实现。无论是接收还是发送,点击取消按钮的结果,都是关闭窗口,因此选择直接使用lambda表达式简化代码。

文件图标

image.png
我是在Clion中构建的的cmake项目。
image.png
需要在构建目录中添加.rc资源文件,并在.rc资源文件中指定IDI_ICON1 ICON "resources/icons/beer.ico"
后面的路径是相对于构建目录的,如果不确定写相对还是写绝对,可以都试一试。

回车发送消息

实现原理就是重写eventFilter方法。
image.png
如果检测到键盘事件,先判断是不是回车,如果是回车就发送消息,如果是CTRL+回车,就插入换行符。
如果是粘贴事件,就尝试插入图片。插入图片有两种可能:

  • 在粘贴板的元数据中
  • 粘贴板存放的是文件地址url

把这两种情况都尝试一遍,如果能获取到图片,那就插入到输入框。
还创建了一个自定义工具类,实现一个静态工具方法imageToBase64。用于将image对象转换为base64格式的字符串,嵌入到html中。

构建多个可执行文件

一个项目构建多个可执行文件,而不是为每一个可执行文件创建新的项目。
这需要修改CmakeList文件,为每一个构建目标指定文件。
image.png
添加自定义目标add_custom_target,允许一次编译所有可执行文件。
image.png
添加可执行文件add_executable,允许一个项目编译生成多个可执行文件。
image.png
括号内,第一个参数LanChatRoom是构建后的可执行文件名。
后面的所有参数,都是参与构建这个可执行文件的源代码文件,包括头文件、源文件、资源文件。之后可能还会导入更多。

条件编译

每次切换debug和release两种状态的时候,都增删代码,是不现实的。
这样项目中每一处需要修改的地方都需要修改。
在最开始的时候,我就是这么做的。把一些调试信息显示在ui上。比如,本来这个标签是显示文件路径的,我现在显示TcpSocket的错误信息。
前面也提了,这个代码重构了很多遍,每次重构的原因,都包括:这一编写的太丑了,乱七八糟的。
重构很多遍之后,才想起来软件设计师备考时学的:软件设计模式。
这种工科的概念,如果脱离实践,那么只是空洞的文字。就算接触到了,也需要重复很多遍才能把认识和实践联系起来。
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
上面这行代码是写在CmakeList中的,它的意思是,在预处理阶段,添加宏DEBUG
在代码中需要调试的地方,用#ifdef DEBUG,进行条件编译。
image.png

窗口程序,不显示cmd

这需要在CmakeList中添加:

set(CMAKE_WIN32_EXECUTABLE TRUE)

否则会携带一个控制台窗口。

动态链接库

这一部分的作用是在编译时链接动态链接库。
并在编译后,把动态链接库.dll复制到目标目录中。

target_link_libraries(LanChatRoom
        Qt::Core
        Qt::Gui
        Qt::Widgets
        Qt::Network
)
target_link_libraries(FileSender
        Qt::Core
        Qt::Gui
        Qt::Widgets
        Qt::Network
)
target_link_libraries(FileReceiver
        Qt::Core
        Qt::Gui
        Qt::Widgets
        Qt::Network
)
if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
    set(DEBUG_SUFFIX)
    if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
        set(DEBUG_SUFFIX "d")
    endif ()
    set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
    if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
        set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
            set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        endif ()
    endif ()
    if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
    endif ()
    foreach (QT_LIB Core Gui Widgets Network)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/bin/Qt6${QT_LIB}${DEBUG_SUFFIX}.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
    endforeach (QT_LIB)
endif ()

实际上,可以只保留target_link_libraries部分。
因为后面一大段的if,作用是导入动态链接库文件,导入的这些仍然是不完整的。
最后需要用windeployqt来补充依赖。用法就是windeployqt [文件名],比如:windeployqt lanchatroom.exe。win环境下是大小写都可以的。
image.png
使用windeployqt需要预先将所在目录添加到环境变量中,以我的电脑为例,windeployqt在目录C:\Tools\Qt\6.6.1\mingw_64\bin下。
也就是Qt版本文件夹下的mingw_64\bin

软件设计模式

我最开始接触,是前段时间准备软考的时候。
重写了这么多编,才对软件设计模式有稍微浅薄的理解。
这里面也用到了策略、状态等模式。
如果没有软件设计模式,那么整个项目将非常混乱。我觉得,从事软件工程,软件设计模式是必须的。

软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

下面是当时汇报的PPT,对其他组的作品也算是降维打击了,哈哈。
LanChatRoom - yuque.pptx

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

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

相关文章

论文阅读:基于MCMC的能量模型最大似然学习剖析

On the Anatomy of MCMC-Based Maximum Likelihood Learning of Energy-Based Models 相关代码&#xff1a;点击 本文只介绍关于MCMC训练的部分&#xff0c;由此可知&#xff0c;MCMC常常被用于训练EBM。最后一张图源于Implicit Generation and Modeling with Energy-Based Mod…

Elasticsearch:带有自查询检索器的聊天机器人示例

本工作簿演示了 Elasticsearch 的自查询检索器 (self-query retriever) 将问题转换为结构化查询并将结构化查询应用于 Elasticsearch 索引的示例。 在开始之前&#xff0c;我们首先使用 langchain 将文档分割成块&#xff0c;然后使用 ElasticsearchStore.from_documents 创建…

IIS通过ARR实现负载均衡

一、实现整体方式介绍 项目中部署在windows服务器上的项目,需要部署负载均衡,本来想用nginx来配置的,奈何iis上有几个项目,把80端口和443端口占用了,nginx就用不了了(因为通过域名访问的,必须要用80和443端口),只能通过IIS的方式实现了。 这里用2个服务在一台机器上…

一个简单的接口自动化测试框架:Python+Requests+Pytest+Allure

项目结构 project&#xff1a;api_test ——api_keyword ————api_key.py&#xff1a;接口关键字驱动类 ——case ————test_cases.py&#xff1a;测试套件和测试用例 ——report_allure&#xff08;无需创建&#xff09;&#xff1a;allure报告 ——result&#xff08;…

git 如何撤销历史某次merge

git&#xff0c;如何 撤销某一次历史提交或merge&#xff0c;并保留该版本的后续提交&#xff1f; 场景1&#xff1a; 你有两个功能迭代版本的分支&#xff0c;一个是 15 号上线&#xff0c;一个是25号上线。5号的时候产品突然说&#xff0c;这两个版本一起上&#xff0c;然后…

【计算机图形学】NAP: Neural 3D Articulation Prior

文章目录 1. 这篇论文做了什么事&#xff0c;有什么贡献&#xff1f;2. Related Work铰接物体建模3D中的Diffusion model扩散模型 3. Pipeline铰接树参数化基于Diffusion的铰接树生成去噪网络 4. 实验评价铰接物体生成——以往做法与本文提出的新指标NAP捕捉到的铰接物体分布质…

gazebo卡住不动

可以看到这个sdf文件里面含有网络连接&#xff0c;有的sdf文件看上去几十个kb, 以为很小&#xff0c;但是里面含有网络连接就不知道有多大了&#xff0c;所以也可能会卡住,然后就会出现这个

无线路由器的五种工作模式:

1.Router&#xff0c;即无线路由模式&#xff0c;这也是我们最常用的一种工作方式&#xff0c;一般家里宽带连接&#xff0c;将宽带猫连接在无线路由的WAN口上&#xff0c;然后做拨号帐号设置&#xff0c;就用这个模式即可。 在Router&#xff08;无线路由&#xff09;模式下&a…

linux下docker搭建mysql8

1&#xff1a;环境信息 centos 7,mysql8 安装docker环境 2.创建mysql容器 2.1 拉取镜像 docker pull mysql:8.0.23 2.2 查询镜像拉取成功 docker images 2.3 创建挂载的目录文件 mkdir /usr/mysql8/conf mkdir /usr/mysql8/data ##给data文件赋予操作权限 chmod 777 /…

关于时间格式yyyy-M-d或yyyy-MM-d到yyyy-MM-dd的转换

工作时遇到前端传的时间格式是"2023-12-3 17:41:52"&#xff0c;和"2023-1-1 17:41:52"但是我想要的是"2023-12-03 17:41:52"和"2023-01-01 17:41:52"。下面给大家分享几个解决方法 方法一&#xff1a; 找前端&#xff01;让他改&…

TCP_可靠数据传输原理

引言 在网络通信中&#xff0c;TCP是确保数据可靠传输的关键协议。但在我们深入研究TCP拥塞控制技术之前&#xff0c;让我们先探索可靠数据传输的原理&#xff0c;特别是TCP头部中一些重要字段的作用。 网络层提供了点对点的通信服务&#xff0c;努力交付数据报&#xff0c;但…

[概率论]四小时不挂猴博士

贝叶斯公式是什么 贝叶斯公式是概率论中的一个重要定理&#xff0c;用于计算在已知一些先验信息的情况下&#xff0c;更新对事件发生概率的估计。贝叶斯公式的表达式如下&#xff1a; P(A|B) P(B|A) * P(A) / P(B) 其中&#xff0c;P(A|B)表示在事件B发生的条件下事件A发生的概…

Android App从备案到上架全过程

不知道大家注意没有,最近几年来,新的移动App想要上架是会非常困难的,并且对于个人开发者和小企业几乎是难如登天,各种备案和审核。但是到底有多难,或许只有上架过的才会有所体会。 首先是目前各大应用市场陆续推出新的声明,各种备案截止日期到12月就要到最后期限责令整改…

wps将姓名处理格式为:姓**

1.打开wps&#xff0c;在要处理数据右侧一个单元格 输入公式&#xff1a;LEFT(A1,1)&"**"&#xff0c;然后回车 2.按住ctrl和处理好的数据的右下角小方框&#xff0c;往下拖动即可生成格式为&#xff1a;姓** 格式的数据 3.复制生成的数据&#xff0c;右键选择 “…

三、HTML元素

一、HTML元素 HTML 文档由 HTML 元素定义。 *开始标签常被称为起始标签&#xff08;opening tag&#xff09;&#xff0c;结束标签常称为闭合标签&#xff08;closing tag&#xff09;。 二、HTML 元素语法 HTML 元素以开始标签起始。HTML 元素以结束标签终止。元素的内容是…

Zero-shot:半监督:pansharpening

Zero-shot semi-supervised learning for pansharpening &#xff08;用于全色锐化的零次半监督学习&#xff09; 全色锐化是指融合低分辨率多光谱图像&#xff08;LRMS&#xff09;和高分辨率全色&#xff08;PAN&#xff09;图像以生成高分辨率多光谱图像&#xff08;HRMS&…

履机乘变,轻舟便楫:源启分布式PaaS深度赋能企业级技术平台建设

导语 源启分布式PaaS平台围绕应用视角为用户提供应用运行的全生命周期管控能力&#xff0c;提供注册中心、服务路由、网关、服务治理等中间件技术支持&#xff0c;实现应用之间的联通&#xff0c;解决客户多厂商产品不兼容、产品组合不可选择、孤岛效应等问题&#xff0c;满足…

CSS animation动画和关键帧实现轮播图效果HTML

CSS animation动画和关键帧实现轮播图效果HTML 这轮播图效果使用h5和css3实现效果&#xff0c;不需要js控制&#xff0c;但是其中的缺点就是不能使用鼠标进行切换效果。 具有代码如下 <!DOCTYPE html> <html lang"en"><head><meta charset&quo…

MACOS Atrust服务异常

MAC版Atrust服务异常 点击进入办公后出现提示其一&#xff1a; 核心服务未启动&#xff0c;部分功能存在异常&#xff0c;确定重新启动吗&#xff1f; 可能的原因&#xff1a; 1.上次已完全退出客户端 2.核心服务被其他程序优化禁用 点击重新启动后&#xff0c;出现提示&#x…

M3u8视频地址如何转为mp4视频

在当今数字化的时代&#xff0c;视频格式的转换已成为日常需求。M3u8格式的视频由于其分段的特性&#xff0c;常常给播放和编辑带来不便。而MP4格式则因其通用性和高质量而广受欢迎。那么&#xff0c;如何将M3u8视频地址转换为MP4格式呢&#xff1f;接下来&#xff0c;我们将为…