代码拉取完成,页面将自动刷新
#项目更新日志
存在较多改动时将在此记录
更新主题:链接池优化
- 原规划:
为实现在链接池查询指定链接功能(用于聊天功能和指定用户推送消息),在链接池中设立多个链表分别存储不同状态的链接(未登录,已登录,断线等待重连),期望以此减少查询消耗,并是能够更方便得管理链接。但发现这种方式会使类的功能变得更复杂,而且链接频繁得切换链表也会造成不必要的消耗- 现:
链接池中仍使用Conn数组存储链接,空闲链接的数组地址将存入线程安全队列中,已使用链接的数组地址存在一个上锁的链表中。当监听服务监听到新的连接时,从空闲链接队列中取出地址,存入已使用链表中,并按照地址将此连接接入该链接中(链接中会保存该链表节点)。业务所需的查询功能将在SQL模块中实现,SQL模块中将会建立一个字典保存登录用户的链接地址<key=用户ID,value=链接地址>,需要时将会在该字典中查询获得。断线重连功能则由线程池实现,线程池将建立一个字典保存意外断开连接的链接/<key=客户端信息,value=链接地址>。链接管理将由链接池的心跳守护线程实现,在遍历使用链接发送心跳消息时也会根据不同的管理策略完成不同的操作(如服务端繁忙时要求用户必须登录等)。此改动能将不同功能区分
更新主题:缓冲区优化
- 物理分配过程:
在物理上所有链接均使用同一个byte数组作为收发缓冲区,在线程池初始化时,线程池会按照配置文件中的链接池链接个数和每个链接收发缓冲区大小初始化byte数组并分配给所有链接
每个链接根据分配到的数组起始地址和配置文件中收发区域大小再由ConnBuffer类分配为接收缓冲区和发生缓冲区,他们的信息由ConnBuffer.BufferInfo类记录
注意:缓冲区一旦分配,直到应用结束运行前都不会再发生改变- 逻辑使用过程:
在逻辑上每个链接分配到的缓冲区分为接收和发送两个缓冲区,ConnBuffer和ConnBuffer.BufferInfo类将这两个缓冲区在使用时经由逻辑运算视为独立的环形数组,从而达到重复使用缓冲区的目的
ConnBuffer类负责管理缓冲区,提供函数实现对缓冲区的操作;ConnBuffer.BufferInfo类记录了单个(接收或发送)缓冲区的起始地址,中止地址,大小,写入位置,读取位置,空闲大小等信息
注意:在操作缓冲区时必须使用ConnBuffer的相应函数,在使用这些函数对缓冲区进行写入、读取数据时,是根据对ConnBuffer.BufferInfo类记录的信息进行计算的结果实现写入和读取- 所有链接使用同一个数组作为缓冲区作用:
1.避免了内存碎片化
2.避免了反复创建数组的消耗,提高内存利用率
3.优化断线重连功能(客户端在移动设备上可能会经常意外断开链接,断线重连是必须做到的功能),已接收的数据和未发送的数据存储在固定的缓冲区中,在意外断开时不会被清除,重连后可以很容易得继续完成
4.在流量高峰期也能提高一定的削峰能力
更新主题:链接消息队列
特别注意注意
:在此处更新中由于发送逻辑发送改变,发送缓冲区不再视为环形数据,每次发送会将发送缓冲区所以内容一起发送,发送缓冲区大小应和MTU大小相适应保证避免内核将数据包自动分包
- 原规划:
在原计划中就规划了消息队列,但只有待处理消息队列,但由于链接的接收的发送均采用异步,为了使发送缓冲区发挥出优势,链接在发送消息时不会立即发送,而是会根据规则(发送缓冲区使用大小达到一定值或达到发送时间)再发送消息,以此减少消息包发送频率- 原规划(链接从接收、处理、到发送流程): 总体:单个链接有两个线程分别完成{线程一:异步接收、解析数据、将得到的消息包放入待处理消息队列;线程二:从待处理消息队列取出消息、按照消息的类别进行不同的业务处理、完成处理后将回发数据打包发送给客户端
- 现规划:
将链接的消息队列单独立为一个类,链接引用此类,类中包含待处理消息队列(注:两个线程都会根据需要向待处理消息队列中添加消息)和待发送消息队列(注:线程二和线程池心跳线程会放入消息到等待发送消息队列)- 现规划(链接流程):
一、总:一个链接依然有两个线程完成所以功能(注意所有线程都将有线程池管理,而非独立的线程,故此处两线程并非独立线程)
二、接收和解析(线程一):
1.异步接收数据(将接收到的数据存入缓冲区);
2.异步接收完成后判断缓冲区内数据是否足够用作解析,若能则解析它们(注:解析过程中任何报错都将视为消息包已被更改,目前无恢复方法,将直接导致该链接断开,因为TCP协议保证了数据不会出错且数据顺序不会乱),解析完成后将得到的消息包放入待处理消息队列
三、处理(线程二):
1.判断待处理消息队列是否存在数据,Ⅰ.若无则跳至准备发送阶段;
Ⅱ.若有则从待处理消息队列中取出消息,根据消息类别在请求字典中查询得到相应方法并交由相应业务模块处理,处理完成后将需返回的数据在请求返回字典中执行相应方法封装打包为消息包 并携带进准备发送阶段;
2.完成处理后若产生附加业务,将该业务打包放入待处理消息队列中(如登录成功后不仅需要返回登录成功消息,还可能需要返回头像文件等消息,此时不会再去读取完成头像文件后再进行步骤1,而是将此操作放入待处理消息队列)
四、准备发送(处理等待消息队列):
1.判断是否携带数据
Ⅰ携带数据,将数据放入等待发送队列,然后进行2
Ⅱ不携带数据,进行2
2.判断缓冲区是否有数据
Ⅰ有则进行4
Ⅱ无则进行3
3.尝试获取等待消息队列首消息包(不移除,此时缓冲区无数据)
Ⅰ成功取出,则将消息包存入发送缓冲区且记录消息包内时间戳,并移除等待消息队列首消息包,然后进行4
Ⅱ取出失败则返回三(处理)
4.尝试获取等待消息队列首消息包(不移除)
Ⅰ成功进行5
Ⅱ失败进行6
5.判断缓冲区能否写入下一个数据包
Ⅰ能则将消息包存入发送缓冲区,并移除等待消息队列首消息包,然后进行7
Ⅱ不能进行五(发送)
6.判断上次发送到现在的时间间隔是否超过发送延时(此时等待发送消息队列无数据)
Ⅰ超过则进行五(发送)
Ⅱ失败则返回三(处理)
7.判断上次发送到现在的时间间隔是否超过发送延时
Ⅰ超过则进行五(发送)
Ⅱ失败则重复4
五、发送
将发送缓冲区所有数据异步发送,发送成功后返回四(准备发送)
- 更新主题:迁移项目(从.NET Framework至.NET Core),添加或使用依赖注入、配置、Json序列化、内存缓存库
- 迁移项目: 将服务端项目从.NET Framework迁移至.NET Core(.NET 5)。其区别参考地址:https://docs.microsoft.com/zh-cn/dotnet/core/porting/
- 添加库或框架: 一、
使用依赖注入
1.库:Microsoft.Extensions.DependencyInjection 二、使用配置
1.库:Microsoft.Extensions.Configuration;Microsoft.Extensions.Configuration.Json; 三、使用新的Json库完成序列/反序列
1.库:System.Text.Json(.NET Core自带)替代Newtonsoft.Json(.NET Framework扩展库); 四、使用内存缓存
1.库:Microsoft.Extensions.Caching.Memory;
- 完成通信模块剩余功能
- 完成客户端相应代码的移植
- 对通信模块功能进行测试并修复调整
- 完成文件模块功能
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。