从文电传输说起

一、故事背景

最近公司对我等新进员工进行考核,形式就是给定一个任务书,完成该软件,语言C++。此次完成的软件大致是通过以太网进行文电传输的东西,其实通俗讲就是类似于飞秋或QQ这样的聊天软件,可以成员管理,广播信息,P2P聊,群聊,文件发送这些(当然,这与相关领域上的文电传输是有区别的)。
考核规定可以在公司做(基础库封装得足够成熟),也可以在家做(没有这么好的库,一切从打地基开始)。想想大致依赖的主要基础操作:网络部分收发、二进制数据流的处理。于是,我决定,秉承我一贯的风格——“抓住一切可以学习的机会”,在家做,其实我就是不想太依赖公司的库,不然以后就对技术只知其然啦(手动捂脸)。
于是,轰轰烈烈的学习旅程开始了,当然,注意时间是在十天内完成啊!

二、故事开始

Question one:我用什么“媲美”公司的基础库呢?

Answer:当然是C++社区里强大的开源库:Boost。毕竟Boost C++ Library是一组基于 C++标准的现代库,平台独立,其支持大多数编译器。要增强C++项目的生产力,除了C++标准以外,Boost C++库是不错的选择。毕竟好几个库都已经进入C++标准,今后还会有更多的库被选中。

学习一门语言,不仅是语法,技巧,还应融入它的生态。

所以,Boost Library是我的不二之选。

Question two:我要封装哪些基础接口呢?

Answer:考虑到是以太网的数据传输,自然少不了网络socket的封装,那socket编程的话,需要依赖一些系统的基本操作,比如线程,定时器,事件机制。
至于对于这些接口,我并不想直接使用Boost的,还是想封装一层,方便应用层面的开发,怎样定接口呢,对于我这还是新手级别的程序员,还是参考参考公司的吧,毕竟是多年的积累。

好的接口让开发事半功倍哦,当然开发好接口也需要相当的经验。

线程、定时器部分:Boost.Thread
事件机制:Boost.Thread + Boost.Signals2
网络编程:Boost.Asio
其他:Boost.Uuid
(当然还有一些必须使用的,如:Boost.Bind)


嗯…一周前三四天下班后就回家搞,然后就是这几个.cpp和.h了。然后下面是个UdpSocket的封装,搞了一个晚上。由于时间限制,我只能封装UdpSocket了。

By the way,下班后回来一门心思地搞,整个人都在亢奋之中,根本停不下来(还好…不加班)

Question three:我这个软件到底要做多“大”呢?

任务书其实说得挺大的,因为内容是用公司某大项目的文档抄下来的(真是直接了,幸好负责人说不懂就照着飞秋或QQ做。)
Answer:
1 从功能上:成员管理,广播信息,P2P聊,群聊,文件发送,分片传输,文件重传要实现,至于安全,保密传输,掂量着短期搞不定啊。
2.从时间上:十天(还得排开上班时间),我要完成系统基础操作做,数据传输、逻辑操作、界面,必须有侧重点了,不能都抓,而我更倾向于前两者。
3.从架构上:这类项目可大可小,看看QQ、微信这类大项目的架构就知道可以有多大了,而想想负责人说其实只需要实现消息收发就可以了,就知道这个项目可真是小了。我现在的能力来讲(毕业几个月的小小个),我做不大,但我要尽我所能做,做好,做规范。

尽吾志者也而不能至,可以无悔也,其孰能讥之乎?

于是,我想到了中间件,作为平台与通信的连接,对上提供特定消息收发的处理,对下封装网络部分的处理,这儿也是考虑到了扩展性,以后TCP封装了后,对于平台的业务逻辑讲,是没关系的。

最终我确认的架构就是这样,采用了订阅者-发布者模式
接下来我的重点是要讲讲文件分片传输部分(最下面那个PacketManager就是我今天讲故事的导火索了)。

三、进入正题(文件分片)

其实就是对Binary Buffer的分片处理,而为什么要分片呢,因为网络上传输是有限制的(后面具体叨叨),不能一大块数据直接就扔过去,其本质是网络协议就定了的,当然也逃不了物理的限制,所以我们必须分片(一包多大,后面叨叨)。

从应用层面理解


这就是一个拆包、组包的活儿,那么一块Buffer分包后,需要知道每个包的序列号,Buffer的总包数,包各自的Length及内容。所以我的PaketHandler就做了这么个拆组包的工作。

#pragma once
#include <map>
#include "DataTransferHandlerExport.h"
#include "Uuid.h"
#include "DataTransferMacro.h"class DATATRANSFERHANDLER_EXPORT CPieceData
{friend class CPacketHandler;public:unsigned char* DataBuffer(void) const;int DataLength(void) const;unsigned short CurrentSequence(void) const;private:CPieceData(void);~CPieceData(void);CPieceData(const CPieceData& rPieceData);CPieceData operator =(const CPieceData& rPieceData);private:void AssignBuffer(unsigned char* pBuffer, int nLength);void ClearData(void);private:unsigned short m_usCurrentSequence;     // 2Byte << A piece of Packet's Current Sequenceunsigned char* m_pDataBuffer;           // N << The Follow Data's Binary Bufferint            m_nDataLength;           //<< The Follow Data's Length
};class DATATRANSFERHANDLER_EXPORT CPacketHandler
{
public:enum{Unit_Net_Data_Defualt_Length = 1024,    // Equal 1KB (A NetPieceData buffer's Max Length)Msg_Head_Fixed_Size = 16 + 2 + 2,       // Head's Length(Fixed)};// Map Parameter: CurrentSequence, NetPieceDatatypedef std::map<unsigned short, CPieceData*> MapPieceData;CPacketHandler(int nUnitLength = Unit_Net_Data_Defualt_Length);~CPacketHandler(void);CPacketHandler(const CPacketHandler& rPacketHandler);CPacketHandler& operator =(const CPacketHandler& rPacketHandler);bool IsDividedPacket(void) const;int CountTotalBufferLength(void) const;CUuid PacketUuid(void) const;int CountCurrentSequences() const;unsigned short TotalSequeceNum(void) const;int UnitLength(void) const;// Record Network InformationDataTransfer::StrucNetworkAddress RemoteAddress(void) const;void SetRemoteAddress(const DataTransfer::StrucNetworkAddress& rStructRemoteAddr);// Dividevoid ResetOffset();              // Re cout Takeout NumberCPieceData* TakeoutPieceData();  // if NULL Take Out Over , Divided Data Finishbool DivideRawDataToPacket(unsigned char* pRawDataBuffer, int nRawTotalLength);// Combinebool IsCombinCompleted(void) const;static CUuid ParseNetDataBufferUuid(const unsigned char* pNetDataBuffer, int nNetDataLength);bool CombineNetDataBuffer(unsigned char* pNetDataBuffer, int nNetDataLength);bool ExportNetToRawDataBuffer(unsigned char** pBufferAddr, int& nTotalLength);private:void ClearAllPieceData(void);// DivideCPieceData* CreateRawPieceData(unsigned char* pRawDataBuffer, int nRawDataLength);bool EncaseRawPieceData(CPieceData& rRawPieceData);private:CUuid          m_PacketUuid;            // 16byte << The Packet's Uuidunsigned short m_usTotalSequenceNum;    // 2 byte << All pieces Sequence Number CountMapPieceData   m_mapPieceData;          //<< The Container of All PieceDatabool           m_bDividedPacket;        //<< Judge The Packet was Divided or Combinedconst int      m_nUnitLength;           //<< A piece of Data's Fixed Length (Divide Use)DataTransfer::StrucNetworkAddress m_StructRemoteAddr;   //<< For Oriented Remote Endpointint m_nDivideRecord;                    // Record Handled Divide Piecesunsigned short m_usCurCombinRecord;     // Record Current Combin Handle Pieces sequence Num
};
/*Divided Packet: PieceData's Buferr = Head + RawDataBuffer;Comes from User LevelCombined Packet: PieceData's Buffer = RawDataBuffer;Comes from Net transfer
*/

而对于应用层面来说,我得支持同时有多块Buffer在发也可能在收(比如同时给两个成员发文件,或同时收多个文件),这就需要对每个包有ID确认了。我使用了Uuid来区别哪个包属于哪块Buffer的。然后用队列,开启收发线程,分包应用层面给的Buffer发送,收到包组合后给应用层面。这就是我的PacketManager干的事儿。(用了观察者模式

#pragma once
#include "DataTransferMacro.h"
#include "TaskAttach.h"class CMsgProcObject;class DATATRANSFERHANDLER_EXPORT CPacketManager
{
public:CPacketManager(void);~CPacketManager(void);void AttachObserver(CMsgProcObject* pObserver);void DetachObserver();bool HandleRawDataBufferForSendReady(const DataTransfer::StrucNetworkAddress& rStructRemoteAddr, // Remote Address For Find Send Endpointunsigned char* pRawDataBuffer, int nRawDataLength);         // Raw Buffer parametersbool HandleNetDataBufferForRecvReady(const DataTransfer::StrucNetworkAddress& rStructRemoteAddr, // Remote Address For Record Sender Endpointunsigned char* pNetDatBuffer, int nNetDataLength);          // Net Buffer parametersvoid ShutdownSendingNetBuffer(const std::string& rStrShutDownSenderIp);void ShutdownRecievingRawBuffer(const std::string& rStrShutdonwRecverIp);private:CPacketManager(const CPacketHandler* rPacketManager) {}CPacketManager& operator =(const CPacketManager& rPacketManager) { return *this; }void OnRecvPacketManage();void OnSendPacketManage();private:CMsgProcObject* m_pObserver;boost::mutex m_MutexRecv;DataTransfer::ListPacketHandler m_listRecvPacketHandler;CTaskAttach m_TaskRecv;boost::mutex m_MutexSend;DataTransfer::ListPacketHandler m_listSendPacketHandler;CTaskAttach m_TaskSend;};

以上就是我对数据分片的代码处理,到当时写完的那个时候,我对分片的认识还很模糊,只知道得这样分,一片是1024*10,然而都没有具体测试过上限。所以下面我对这个进行了一些思考。
还听下篇故事继续走。

从文电传输说起(一)相关推荐

  1. 智慧军营信息系统建设方案

    智慧军营是为了 信息备战,战为目的,重在信息主导和倍增战斗力,打牢体系根基,提高基于信息系统的快速感知.快速反应.快速行动能力 快速感知 以"五率六量"(人员在位率.装备完好率.装 ...

  2. 北京智慧军营信息化管理系统软件解决方案

    北京智慧军营信息化管理系统软件解决方案 智慧军营信息化管理系统军区营区对进出营区的人员,车辆实现一系列信息化管理,通过一卡通系统平台实现人员和车辆进出营区授权控制,在此基础上增加开发一系列实用于军区管 ...

  3. Linux系统管理必备知识之利用ssh传输文件

    在使用SSH时候,有时我们需要传输文件,这就需要用到命令scp. 从服务器上下载文件 scp username@servername:/path/filename /local_dir(本地目录) e ...

  4. http传输json文件_python

    https://cloud.tencent.com/developer/article/1571365 http传输图片 https://www.cnblogs.com/jruing/p/122156 ...

  5. python命令之m参数 局域网传输

    在命令行中使用python时,python支持在其后面添加可选参数. python命令的可选参数有很多,例如:使用可选参数h可以查询python的帮助信息: 可选参数m 下面我们来说说python命令 ...

  6. 王道考研 计算机网络笔记 第五章:传输层

    本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...

  7. 光学传输与摄像头光学技术

    光学传输与摄像头光学技术 时域全反射和波导 麦克斯伟方程在时间和空间具有一定的对偶性(duality),比如空间上高斯光束的衍射与时间上高斯脉冲在具有负群速度色散的光纤中传输就具有这样的关系.科学家们 ...

  8. Thrift协议与传输选择

    1 协议 Thrift 可以让用户选择客户端与服务端之间传输通信的消息协议类别,如我们前面所讲总体划分为文本 (text) 和二进制 (binary) ,为节约带宽,提高传输效率,一般情况下使用二进制 ...

  9. 如何 SQL Server 2005 实例之间传输登录和密码

    INTRODUCTION 本文介绍如何不同服务器上的 Microsoft SQL Server 2005 实例之间传输登录和密码. 本文, 服务器 A 和服务器 B 是不同的服务器. 此外, 服务器 ...

最新文章

  1. (广州)软件开发定制服务,工作流引擎 OA 库存管理系统
  2. WSUS Troubleshooting guide
  3. 四川300家旅游企业将用上阿里云
  4. python去除rpm仓库中同名低版本的包
  5. Python - 利用pip管理包
  6. java oauth2登录以及权限_还得看 Java!Gitee 4月最火 Java 项目大盘点
  7. mysql error 1837_MySQL 主从复制错误1837
  8. ES6 数组高频使用方法
  9. CF1039E Summer Oenothera Exhibition
  10. 发那科机器人xyz的方向_发那科机器人应用-机器人坐标系介绍(4)
  11. 使用c#语言进行游戏开发,Unity 3D脚本编程——使用C#语言开发跨平台游戏
  12. 网易云计算机系统有限公司,网易云音乐官方电脑版
  13. 安全知识竞赛答题小程序
  14. Securing Services with Spring Cloud Gateway
  15. python中oct函数_Python内置函数OCT详解
  16. dell云存储服务器,dell云存储服务器(戴尔存储服务器)
  17. lstm不收敛_LSTM学习笔记
  18. 执行git reset --hard后文件的恢复
  19. MySQL聚簇索引和非聚簇索引的原理及使用
  20. UNP卷一chapter17 ioctl操作

热门文章

  1. vue2 使用 oninput onChange报错Uncaught ReferenceError: oninputHandler is not defined
  2. MAC Tree 命令的使用
  3. 云视通开放平台对应终端都应该使用什么协议播放
  4. 应用案例 | 基于TSN和以太网的汽车E/E架构设计
  5. 用python画一个双层圆环筒状闭环源码
  6. 开涛的springMVC教程读书笔记
  7. java计算机毕业设计线上远程教学及自主学平台的设计与实现源码+系统+数据库+lw文档
  8. 采用计算机数控技术的自动控制系统为,数控加工编程技术期末考试综合复习题...
  9. win10静态arp绑定
  10. 爱数助力中国银行苏州分行信息化建设