如何使用网络库实现应用级消息收发

网络客户端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.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Seebug漏洞平台

TP-LINK 远程代码执行漏洞 CVE-2017-13772 趣谈

原文地址:《A CURIOUS TALE OF REMOTE CODE EXECUTION, THE TP-LINK STORY – CVE-2017-1377...

1.4K6
来自专栏小白安全

web渗透思路及总结

(一)针对网站程序,不考虑服务器。 一、查找注入,注意数据库用户权限和站库是否同服。 二、查找XSS,最近盲打很流行,不管怎样我们的目的是进入后台。...

6827
来自专栏偏前端工程师的驿站

.Net魔法堂:开启IIS的WebGarden、WebFarm和StateServer之旅

前言                                 公司系统虽然配置有1台NLB后拖4台App Server最后搭一台强劲无比的DB Serv...

2847
来自专栏HappenLee的技术杂谈

LVS-NAT模式的配置详解

由于实验室拟态存储的项目需要通过NAT模式来映射NFS服务器已实现负载均衡的目的,通过调研了多种负载均衡机制,笔者最终选择了LVS的NAT模式来实现需求,接下来...

1213
来自专栏FreeBuf

Kali 2.0 安装与使用指南

关于kali使用前的一些配置,网上有很多版本,但是几乎都很雷同,或者是不全,或者是根本就没有测试过,或者是有的方法是错的(换句话说是版本变化的差异),因此让很多...

9445
来自专栏Golang语言社区

Web 最常见安全知识总结

随着Web2.0、网络社交等一系列新型的互联网产品的诞生,基于Web环境的互联网应用越来越广泛,企业信息化的过程中,越来越多的应用都架设在Web平台上。Web业...

37512
来自专栏Laoqi's Linux运维专列

Zabbix的架构配置选项(二)

3018
来自专栏智能大石头

如何使用网络库实现应用级消息收发

网络客户端ISocketClient和网络会话ISocketSession都继承了ISocketRemoteISocketRemote表示远程通信,核心就是收发...

620
来自专栏流柯技术学院

Android APP测试的日志文件抓取

  实时打印的主要有:logcat main,logcat radio,logcat events,tcpdump,还有高通平台的还会有QXDM日志

3851
来自专栏.NET技术

winserver的consul部署实践与.net core客户端使用(附demo源码)

随着微服务兴起,服务的管理显得极其重要。都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的服务,每个服务可以在短周期内重构、迭代、交付。随着微服务的数...

1312

扫码关注云+社区

领取腾讯云代金券