为什么80%的码农都做不了架构师?>>>   

网络客户端ISocketClient和网络会话ISocketSession都继承了ISocketRemoteISocketRemote表示远程通信,核心就是收发数据。
下面是ISocketRemote接口的主要实现

/// <summary>远程通信Socket,仅具有收发功能</summary>
public interface ISocketRemote : ISocket
{#region 属性/// <summary>远程地址</summary>NetUri Remote { get; set; }/// <summary>通信开始时间</summary>DateTime StartTime { get; }/// <summary>最后一次通信时间,主要表示会话活跃时间,包括收发</summary>DateTime LastTime { get; }/// <summary>缓冲区大小</summary>Int32 BufferSize { get; set; }#endregion#region 发送/// <summary>发送数据</summary>/// <remarks>/// 目标地址由<seealso cref="Remote"/>决定/// </remarks>/// <param name="pk">数据包</param>/// <returns>是否成功</returns>
    Boolean Send(Packet pk);#endregion#region 接收/// <summary>接收数据。阻塞当前线程等待返回</summary>/// <returns></returns>
    Packet Receive();/// <summary>数据到达事件</summary>event EventHandler<ReceivedEventArgs> Received;/// <summary>消息到达事件</summary>event EventHandler<MessageEventArgs> MessageReceived;#endregion#region 数据包处理/// <summary>粘包处理接口</summary>IPacket Packet { get; set; }/// <summary>异步发送数据并等待响应</summary>/// <param name="pk"></param>/// <returns></returns>Task<Packet> SendAsync(Packet pk);/// <summary>发送消息并等待响应</summary>/// <param name="msg"></param>/// <returns></returns>Task<IMessage> SendAsync(IMessage msg);#endregion
}

一、同步收发
一般小型网络应用,或者个人学习程序,都会使用同步收发。
Send(xxx);
var buf = Receive();
这样向对服务端发一个数据包,然后同步阻塞等待接收一个响应数据。
同步收发最大的优点就是简单,容易理解;
最大的缺点是性能极其底下,并且很大的几率会失败抛出异常,特别是离开本机或者局域网以后。
除非网络很干净,客户端服务端只进行很简单的通信,否则出错崩溃就是家常便饭!
并且,这个阶段的工程师,一般认为只能客户端向服务端发数据,而不知道服务端可以主动向客户端发数据。

因此,15年经验表明,同步收发根本不适合做产品级应用!

二、事件驱动
中大型网络应用,一般采用事件驱动,特别是多并发服务端。
不管是APM还是SAEA,绝大多数网络框架都会包装成为事件,或者路由分发架构。
正如前文接口图黄色箭头所示,事件驱动一般用法:
client.Received += OnReceive;
client.Send(xxx);
先建立接收事件,然后发送数据,如果对方有响应,就会触发OnReceive函数,对响应结果进行处理。

事件驱动(包括路由分发)是当下网络框架主流,占比超过70%
几乎所有框架都会在此之外再包装一层,Send一个业务对象,内部序列化为数据后发出,OnReceive后反序列化得到业务对象,返回给上层。

事件驱动跟同步业务需求是相背而行的。
如果业务需要向服务端发送一个请求,然后等待响应结果,那么事件驱动甚至还不如同步操作好用!
一般做法是Send里面做堵塞等待,然后OnReceive里面做拦截。
这也是事件驱动无法进一步扩大比例的根本原因。

事件驱动很好很强大,只是特别不适应业务上的同步操作需求!

三、异步请求响应
近20年的软件发展史,无一例外等同于Web发展史。
除了技术的发展,Web思维影响了几乎所有软件工程师。哪怕初学者,也很清楚HTTP是请求响应模型。在Web开发里面,所有的业务都要基于请求与响应。

于是我们网络库有了第三种选择。(前文接口图紫色箭头)
Task<Packet> SendAsync(Packet pk);
Task<IMessage> SendAsync(IMessage msg);
event EventHandler<MessageEventArgs> MessageReceived;

异步发送SendAsync,可以像事件模型那样在MessageReceived里面处理,也可以 var rs = await SendAsync(pk); 把异步转为同步操作,满足同步业务需求。

更为重要的是,SendAsync支持单连接通道并行多异步请求
也就是说,在一个网络连接上,第一个请求的响应还没有收到之前,业务逻辑可以连续发出更多的请求,不管这些请求的响应包先后顺序以后,网络库都能够准确配对,让await SendAsync得到正确的结果。
这就解决了一个极为常见的问题,一个业务应用里面,可能多个线程需要向服务端请求数据,而传统做法只能是加锁,在第一个请求响应完成之前,阻塞其它请求。

实际上,HTTP 1.0/1.1正是传统做法,前一个请求完成之前,不能发起新的请求,导致浏览器不得不建立多个Tcp连接。

因此,异步请求响应的架构设计,让请求响应准确配对,支持并行请求,并且解决一切粘包问题!

应用级消息收发伪代码:

var str = "{action:Open,args:{index:3},remark:打开3号灯}";
var client = new NetUri("tcp://127.0.0.1:1234").CreateRemote();
client.Packet = new DefaultPacket();
var rs = await client.SendAsync(str.GetBytes());
// rs = "{result:true,data:3号灯已打开}"

上面的DefaultPacket正是 新生命团队标准网络封包协议
请求响应包的头部,都会增加4字节,Json字符串作为负载数据。
正是增加的这4字节,确保了请求响应的准确配对(序列号匹配),解决了粘包问题(头部长度)

即使没有默认封包DefualtPacket,上面代码也是可以工作的,只是这样就失去了准确配对和粘包拆分,要求业务层不能频繁收发。

End.

转载于:https://my.oschina.net/nnhy/blog/1591897

如何使用网络库实现应用级消息收发相关推荐

  1. 《Linux多线程服务端编程:使用muduoC++网络库》学习笔记

    文章目录 第1章 线程安全的对象生命期管理 1.1 当析构函数遇到多线程 1.1.1 线程安全的定义 1.1.3 线程安全实例 1.2 对象的创建很简单 1.3 销毁很难 1.4 线程安全的Obser ...

  2. 谷歌开源张量网络库TensorNetwork,GPU处理提升100倍!

    编译 |  琥珀 出品 | AI科技大本营(ID:rgznai100) 世界上许多最严峻的科学挑战,如开发高温超导体和理解时空的本质,都涉及处理量子系统的复杂性.然而,这些系统中量子态的数量程指数级增 ...

  3. 多数据中心的百万级消息服务实战

    背景 利用RabbitMQ集群横向扩展能力,均衡流量压力,让消息集群的秒级服务能力达到百万,Google曾做过此类实验:有货在某些推送场景下也做了类似尝试,在此对此前实践经验以及踩得坑做些总结工作. ...

  4. 干货 | 金融级消息队列的演进 — 蚂蚁金服的实践之路

    小蚂蚁说: 消息队列作为一个数据的集散中心,承载了越来越多的场景和数据,从最开始的 OLTP 到 OLAP,甚至再到物联网.人工智能.机器学习等场景,都有很大的想像空间. 在能力上,消息队列现在拥有了 ...

  5. 技术实践 | 聊聊网易云信的信令网络库实践

    导读:信令作为实时音视频技术架构中的重要一环,是对建立实时音视频通信起到关键桥梁性的作用. 文|丁永锋 网易云信资深客户端开发工程师 本文将从信令的概念着手,分享在网易云信新一代音视频技术架构下,信令 ...

  6. muduo网络库学习(七)用于创建服务器的类TcpServer

    目前为止,涉及到的绝大多数操作都没有提及线程,EventLoop,Poller,Channel,Acceptor,TcpConnection,这些对象的执行都是在单独线程完成,并没有设计多线程的创建销 ...

  7. muduo网络库学习(三)定时器TimerQueue的设计

    Linux下用于获取当前时间的函数有 time(2) / time_t (秒) ftime(3) / struct timeb (毫秒) gettimeofday(2) / struct timeva ...

  8. 客户端网络库实现真的很简单吗?

    (注:本文所讲的网络协议只针对TCP协议) 背景:开发一个C/S的应用势必需要服务端和客户端的适配,包括网络协议.数据传输格式.业务处理的适配.由于服务端承载着大量的客户端,需要高并发.高性能.高可靠 ...

  9. .NET Core使用IO合并技巧轻松实现千万级消息推送

    之前讲述过多路复用实现单服百万级别RPS吞吐,但在文中有一点是没有说的就是消息IO合并,如果缺少了消息IO合并即使怎样多路复用也很难达到百万级别的请求响毕竟所有应用层面的网络IO读写都是非常损耗性能的 ...

最新文章

  1. iis6如何升级iis7_IIS修复IIS出现错误后如何完全卸载重装
  2. struts2 action间跳转传值
  3. 深度学习分布式策略优化、显存优化、通信优化、编译优化综述
  4. Apollo进阶课程⑪ | Apollo地图生产技术
  5. 【UOJ139】【UER #4】被删除的黑白树
  6. 我的《野蛮生长》书摘
  7. CMU和谷歌联手放出XL号Transformer!提速1800倍 | 代码+预训练模型+超参数
  8. Django模板渲染错误
  9. 计算机制作幻灯片视频教程,如何在电脑上制作幻灯片?
  10. 微信web端生成支付二维码
  11. 【洛谷】P3387 【模板】缩点
  12. vba按原格式批量合并word文档
  13. Direct3D中的光照
  14. 笔迹鉴定流程,都需要什么,费用多少?
  15. 数据结构中频度的详细总结
  16. CSS 添加背景图片
  17. docker/Dockerfile/docker compose
  18. 去哪儿 android,去哪儿网无线端再发力 为Android配“旅行助手”
  19. 怎么把多个JPG合并成一个PDF?还不快来学
  20. Linux 命令(57)—— objdump 命令

热门文章

  1. boost::gregorian模块实现日期相关的测试程序
  2. GDCM:gdcm::Validate的测试程序
  3. VTK:非结构化网格之UGrid
  4. VTK:Filtering之ProgrammableFilter
  5. OpenCV反向项目功能用法的实例(附完整代码)
  6. OpenCV连接的组件Connected Components的实例(附完整代码)
  7. OpenCV使用FacemarkAAM
  8. OpenCV检测平面物体
  9. OpenGL基于PBR的irradiance辐照度的实例
  10. C++large fibonacci大斐波那契数列的实现(附完整源码)