| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> TCP通讯中发送文件 -> 正文阅读 |
|
[网络协议]TCP通讯中发送文件 |
一开始写我就觉得这个功能特别鸡肋,TCP传送文件,没办法需要这样的功能,只要硬着头皮上了,如果不是有这个需求,我肯定会骂人,真不是多余嘛!好了言归正传,直接说在TCP通讯中文件发送是如何应用的。 需要的功能:客户端 -->> 服务器 发送文件 开发环境:VS2017 + QT5.14.2 开发语言:C++ 实现这个功能,我们会遇到哪些主要难解决的问题呢? 1:文件过大怎么办? 2:传输中断怎么解决? 3:传输过程中,界面卡死怎么处理? 4:文件发送过去,服务端如何处理呢? 以上是我在实现发送文件功能时遇到的问题,在后续文章也会对此一一解答。如果还有其他不懂的问题可以留言告诉我,一同探讨解决。 1:定义通讯协议TCP通讯中,连接服务器与客户端的桥梁便是通讯协议。定义一个简单明了的通信协议对我们实现功能来说也是事半功倍。 说到了发送文件,那么我们可以假设发送文件的通讯命令字是A1。 首先,在发送文件内容之前,我们需要将文件的名称、大小发给服务器。 我们可以定义一个json结构发送
上述结构体中,fileName存储了需要发送的文件名称,使用string类型表示;fileSize存储了需要发送文件的大小。 其次,后续直接发送带有命令字A1的实际文件内容。为了快速传送,假设一次最多可发送40960个真实内容。 以上,我们就将发送文件的通讯指令建立了。下面开始直接使用 2:给服务器发送文件信息第一步,读取需要发送文件的大小。
第二步,将有效数据组成json结构体字符串数据 json数据序列化以及反序列化的功能,大家应该都不陌生,这里我也写出来了。 在使用json功能之前,记得要添加 #include "json.h"
写法很简单,不用我再过多说明了。 但是需要注意一点的是:通讯过程中必须要使用utf8格式的编号。这里我没写出来,大家可以用C++方法也可以用QT方法,QT的方法会更快捷一些。毕竟在这里我用的是VS+QT的开发环境。 第三步,给服务器发送信息
以上代码是将json数据转成char数据数据进行发送的过程。 InitHeaderData():这里存放的是20位预留字节,是在开放过程中防止后续有添加,根据个人需求设置。 24、25、26 三个字节存放文件的大小,为了防止传送较大的文件。 对于我的理解来说,难点在于如何将json字符串数据赋值到char数组中,其他的都是很简单的。 3:给服务器发送文件内容这一步骤是比较难理解的,涉及到了页面显示效果。 当我们发送一个很小的文件时,消息很快就发送了,几乎不会造成页面卡顿。但是在发送一个大一些的文件时,就会出现这个问题。 第2阶段实现完成后,我们需要进行以下操作向服务器发送有效文件内容。 第一步,我们需要将文件指针恢复到头位置
原因:是因为在读取整个文件大小时,文件指针的位置已经到了文件的末尾。发送实际内容时需要从开始发送。 第二步:定义文件发送时需要的变量 在发送文件时,我们都需要知道哪些呢?
文件的总体大小nTotalSize、记录每次读取的文件内容chFileBuffer、文件指针移动的位置以及是否成功标识帮助我们跳出循环。 第1阶段已经说明了我们在每次读取时最多取40960个有效内容,这里的g_nMaxSendByte = 40960; 第三步:读取文件并发送 读取文件之前我们需要将chFileBuffer中的旧数据置空,好习惯一定要养成。
获取读取当前发送的实际大小。 这是一个三目运算符操作,主要是我太懒了,不想写if、else语句,哈哈。 意思就是说:当文件的总大小 < 40960个长度时,读取的文件内容是文件的总大小,反之就是40960个长度
记录需要移动的文件指针大小
从文件中读取刚刚计算的内容
将读取的文件内容(chFileBuffer)发送给服务端。 发送方法和发送json数据的格式差不多,最主要的差别在于,这里是发送的是char数据。那么我就把如何将char数组赋值到char*数据这部分说明下
发送成功文件后,记得从总文件大小中减去已经发送的大小。当文件大小为负数时,说明文件已经发送完成
将文件的指针进行偏移
在正常情况下,while循环发送的主要内容就这些了。 为什么说是正常情况呢?万一文件传输过程中,与服务器断开连接了呢?这时,我们就需要判断socket是否有有效数据,如果socket == INVALID_SOCKET,也需要跳出循环 接下来展示整体的循环发送文件内容
4:界面卡死处理当我们使用上述方式发送一个较大的文档时,肯定会出现界面卡死的现象。这也是C++在程序处理过程中最头疼的一部分了。 开线程,这是我第一次在写这个功能时第一时间想到的解决方法。但是,我又想到假设我写的这个程序中有很多加载数据慢的地方,也不一定都是传送文件,可能是其他的功能。我还有线程满天飞吗?仔细想想我都头疼。后来我采用的是"QtConcurrent::run"的方法,之前的文章中我也提到过。这里使用方式我不再过多说明,只是提供一个方向。 在发送文件时,一遍加载等待页面一遍发送文件内容,使用进程的方式处理,比开线程简单多了。 5:服务器接收客户端发送的文件信息第一步,定义接收数据结构体 首先,我们需要记录文件信息,也就是文件名称、文件大小以及已经接收的文件大小。数据量较多,这里采用的结构体进行存储。
客户端与服务器一般都是多对一的关系,我们在服务端这边记录客户端数据时采用了std::vector<ServerDeviceFilesInforSt> m_vetInfo 成员变量。根据实际使用习惯可以定义其他容器比如:map、list 第二步,记录客户端发送的文件信息 首先,从众多的客户端中查询出当前发送消息的客户端
当我们查询到匹配客户端后,如果当前在结构体中记录的总体文件大小 ==0时,说明是第一次存储文件的基本情况,解析数据并进行存储
第三步,记录实际文件信息 当结构体中的文件总体大小不为0时,说明正在接收实际的有效数据 获取接收真实的文件大小
将接收的内容存储到文件指针中存储
记录到文件指针后记录已经接收的实际长度
当服务端记录的文件大小 <= 接收的大小时,说明文件接收完成
以上便是服务端接收的实际操作。 今天的TCP传送文件操作已经讲解完成。虽然功能很鸡肋,就当自己提升了一下通讯水平。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/28 6:39:55- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |