P2P分布式资源存储项目设计收获

88 篇文章 2 订阅
32 篇文章 0 订阅

共享项目收获总结

这是一个局域网分布式资源存储项目,没有涉及外部P2P的穿墙技术.

得失
目的
技术道路

起源

一直希望在P2P上有所进展.
特别某次思考到分布式计算的设计.
留下了一个思考框架在笔记中.

此次正值上份更新完成空档时间,看了下最近的项目需求是减少流量,而局域网P2P是个有效措施,
遂向领导申请做此事.
开始进行预研.

结果

本项目:
总行数: 4300
代码规模:2600

实际编程历时在:三周.
28,29,30,31,18,
19,20,21,22,25,
26,27

作为对比:Proxy项目:
总行数:5200.
代码规模:3400.

另一个对比是RPC项目
总行数: 4200
代码规模:2300
历时:两周+

效率评估

时间不是太长.提升很大.基本都在设计和实现中.

设计得与失

从时间上来说没什么太大问题.
但是前期设计还是费了不少时间.

跨进程请求

为了稳定性,独立服务端目的,因为有同机有多个程序在不同阶段需要调用P2P下载服务.
如果再组织一个跨进程通信…太麻烦了:其实可以通过共享内存来处理.原因是我没有做过这个…
这里采用的措施是:
将下载需求放入配置文件中…

下载文件管理

ini中hash作为key.也算是一个好设计.

通信层选择

经历:

  • MailSlot
    切换原因:
    受限制的发送长度.
    不能适应多端通信.没有单独的向不同客户端通信的设计.
    导致一次只能向一端通信,即使这样也不太方便切换端.
    也就是KD-RPC设计的时候只考虑了向单一服务器通信.
    改进方向是:在通信层上增加不同的目标地址.
    此外其设计上偏重于发送数据给服务器.而不是从服务器拉回数据.
  • Pipe
    切换原因:
    受限制的网络服务.
    以为这个可以不限制通信长度.从资料中了解到它跨机限制长度后:改成服务器回复使用:分片发送.限制客户端的发送长度.
  • Socket
    沿用了客户端发送请求限制在一个包里,收到即返回.

如果能更早的使用Socket来做处理可少走很多弯路.
这是一条经验.

三种选择.
通信层至少花费4天时间.后期会更快.

预研效果

前期预研主要集中在通信结构设计.
初步研判:这也是KD-RPC即不能很好的表达从服务器上拉回数据这一需求.
测试用例仅存在于最外部,导致内部代码轻易改动不了.

任务分为如下:

  • 新的通信结构的设计
  • 新的通信协议封装

总体上预研还是不错的.特别是在定下结构为项目设计.
使用空函数的方式使得逻辑能呈现在代码中,并在后续过程中陆续对空函数进行实现.
空函数使用了异常抛出来防止误用.

长连接->短连接

早期设计是长连接.

与特定客户端的通信,不是每次都关闭.

即组成P2P网.但是由于一些考虑,导致无法做合理复用,只能使用短连接暂时解决.

单元测试

真正做到了类级单元测试.
这极大地改善了代码的可靠性,
为代码的稳步建构提供了保障.

设计艺术之骨架先行

性能改善

主要遇到过以下性能问题:

  • 内存管理
  • 扫描局域网范围
  • 缩小范围
  • 无法缩短时间的阻塞类请求
  1. 将对象指针作为参数传给多线程.
  2. 无论成功失败都将在设置对象数据后退出线程
  3. 统一等待所有线程退出.
  4. 循环检查各个线程的结果.
    //这里可以优化,现在的检查方案是:没有成败独立标识,直接操作句柄,导致异常来判断.
    //应该改为更有效率的标识法.

通信结构设计-效率至上

由于我们采取了std::string作为存储的方式,
所以实际上并不太方便使用位处理和直接指针读取,eg:DWORD* 直接读的方式很不友好.

本次采取的是:完全是可视字符串处理.
虽然增大了那么一点的大小.但是相对于整体的安全和实现便利 来说是值得的.

MAGIC	6
MainVersion 1	;主版本不匹配直接就返回错误了.
SecondaryVersion 1
PackageLength	10 ;10个十进制数字可以表达0xFFFFffff的范围
status	3	;类型网络状态码:200,300之类所以占3个字符
MainType	8
SecondType	8
OtherData	...

前期设计是按位处理,但是在添加\0的时候感觉不爽.来回转换也不好.
直接用"."来补位空缺.

最终本格式设计可以快乐的集成在任一通信层上了.比如JS之类也方便实现.
难道是因为我被JS荼毒?

类设计的新探究

  • 首次使用其他类指针作为构造函数参数
    用于处理A依赖B的关系.顺带学了UML.

CFormat和CClient类遇到一个另人困惑的设计.

CClient依赖具体CFormat.原本打算用CClient继承CFormat,但是想了一下这样很不合理.
因为CFormat需要被继承多态处理,而CClient也需要被继承多态处理.
总不能人家对CFormat继承时被迫对CClient也继承?相对不合理.

所以当想到以上设计时,惊为天人.

知识所得

这就是不按照经典书籍走的后果,会遗漏很多细节.
以下两处所得也是本次遗漏的细节

std::string作为内存管理器

C++ 创建对象的三种方法之栈中分配

  Test test1; //隐式调用,栈中分配 ,由操作系统进行内存的分配和管理
  Test test2 = Test; //显式调用,栈中分配 ,由操作系统进行内存的分配和管理
  Test *test3=new Test(); //堆中分配 ,由管理者进行内存的分配和管理,用完必须delete(),否则可能造成内存泄漏

之前以为栈中分配是不调用构造函数的,其实并不是.
这是在调试Socket通信的例子时发现的.
这一解决了我的疑问:std::string 为什么不new也能快乐的玩耍.

Socket代码也并不复杂

在网络层中尽早使用 Socket是有益的。

如何将一个类作为参数传入方法中

好吧,终究还是回来了.
当年难以理解和掌握的知识点,随着实践的增加一定更容易习得了.
使用的是类的引用:

事后诸葛

如果再次设计,我会:

  • 保持类级单元测试
  • 使用基本的Socket协议做通信
    简单淳朴不浪费时间
  • 时间预估上:
    P2P协议类通信类:4000行:10天/2周+预研1周+测试1周=4周.

总结

本次设计颇有收获,不仅仅是具体语言更细节的使用上.
也在设计上增长了经验.在测试上增加了.

掌握一门语言从其经典书籍中确实能掌握很多细节.
之前认为这些细节并不必要.
即使已经3年工作经验的我依然遭遇了很多难题却浑然不知.
如果能伏下身潜心做一些细致的基础学习,会有很大提升.

基础学习 和 开源代码的研读相互推动,自己迈向更高的台阶.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值