企业级工作流解决方案(八)--微服务Tcp消息传输模型之服务端处理
服务端启动
服务端启动主要做几件事情,1. 从配置文件读取服务配置(主要是服务监听端口和编解码配置),2. 注册编解码器工厂,3. 启动dotnetty监听端口,4. 读取配置文件,解析全局消息处理模型5. 注册服务端处理对象到容器。
JsonRpcServerModule代码如下,见备注说明
[DependsOn(typeof(AbpKernelModule))]
public class JsonRpcServerModule : AbpModule
{
public override void PreInitialize()
{
// 注册客户端配置,固定从Xml文件读取
SocketServiceConfiguration socketServiceConfiguration = XmlConfigProvider.GetConfig<SocketServiceConfiguration>("SocketServiceConfiguration.xml");
IocManager.IocContainer.Register(
Component
.For<ISocketServiceConfiguration>()
.Instance(socketServiceConfiguration)
);
IocManager.Register<IServiceExecutor, DefaultServiceExecutor>(Dependency.DependencyLifeStyle.Singleton);
} public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(JsonRpcServerModule).GetAssembly());
var socketServiceConfiguration = Configuration.Modules.RpcServiceConfig();
switch (socketServiceConfiguration.MessageCode) // 根据配置文件,编解码配置选择
{
case EMessageCode.Json:
IocManager.RegisterIfNot<ITransportMessageCodecFactory, JsonTransportMessageCodecFactory>(Dependency.DependencyLifeStyle.Singleton);
break;
case EMessageCode.MessagePack:
IocManager.RegisterIfNot<ITransportMessageCodecFactory, MessagePackTransportMessageCodecFactory>(Dependency.DependencyLifeStyle.Singleton);
break;
case EMessageCode.ProtoBuffer:
IocManager.RegisterIfNot<ITransportMessageCodecFactory, ProtoBufferTransportMessageCodecFactory>(Dependency.DependencyLifeStyle.Singleton);
break;
default:
break;
} RegisterDefaultProtocol();
} public override void PostInitialize()
{
var socketServiceConfiguration = IocManager.Resolve<ISocketServiceConfiguration>();
// 方法里面调用ServiceHost构造函数传入的委托,启动dotnetty监听
IocManager.Resolve<IServiceHost>().StartAsync(new IpAddressModel("0.0.0.0", socketServiceConfiguration.Port).CreateEndPoint()); // 从配置文件读取json-rpc服务配置,解析消息处理模型
JsonRpcRegister.LoadFromConfig(IocManager);
} private void RegisterDefaultProtocol()
{
var dotNettyServerMessageListener = new DotNettyServerMessageListener(Logger,
IocManager.Resolve<ITransportMessageCodecFactory>(), IocManager.Resolve<ISocketServiceConfiguration>()); IocManager.IocContainer.Register(
Component
.For<IMessageListener>()
.Instance(dotNettyServerMessageListener)
); var serviceExecutor = IocManager.Resolve<IServiceExecutor>(); // 新建一个ServiceHost对象,放入容器,这个时候dotnetty还未启动,只是定义了执行方法。
var serverHost = new DefaultServiceHost(async endPoint =>
{
await dotNettyServerMessageListener.StartAsync(endPoint); // 启动dotnetty监听
return dotNettyServerMessageListener;
}, serviceExecutor); IocManager.IocContainer.Register(
Component
.For<IServiceHost>()
.Instance(serverHost)
);
}
}
Dotnetty启动监听代码,参考dotnetty提供的实例代码,ServerHandler为自定义消息处理Chanel
/// <summary>
/// 触发接收到消息事件。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">接收到的消息。</param>
/// <returns>一个任务。</returns>
public async Task OnReceived(IMessageSender sender, TransportMessage message)
{
if (Received == null)
return;
await Received(sender, message);
}
public async Task StartAsync(EndPoint endPoint)
{
_logger.Debug($"准备启动服务主机,监听地址:{endPoint}。"); IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1);
IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2
var bootstrap = new ServerBootstrap(); bossGroup = new MultithreadEventLoopGroup(1);
workerGroup = new MultithreadEventLoopGroup();
bootstrap.Channel<TcpServerSocketChannel>();
bootstrap
.Option(ChannelOption.SoBacklog, _socketServiceConfiguration.Backlog)
.ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
.Group(bossGroup, workerGroup)
.ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
{
var pipeline = channel.Pipeline;
pipeline.AddLast(new LengthFieldPrepender(4));
pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4));
pipeline.AddLast(new TransportMessageChannelHandlerAdapter(_transportMessageDecoder));
pipeline.AddLast(new ServerHandler(async (contenxt, message) =>
{
var sender = new DotNettyServerMessageSender(_transportMessageEncoder, contenxt);
await OnReceived(sender, message);
}, _logger));
}));
try
{
_channel = await bootstrap.BindAsync(endPoint);
_logger.Debug($"服务主机启动成功,监听地址:{endPoint}。");
}
catch
{
_logger.Error($"服务主机启动失败,监听地址:{endPoint}。 ");
}
}
消息最终经过解码处理之后,会落到DefaultServiceExecutor类进行处理,在这里调用JsonRpcProcessor静态类的Process方法,处理Json-Rpc请求,并构造答复消息,答复客户端。
public class DefaultServiceExecutor : IServiceExecutor
{
private readonly ILogger _logger;
public DefaultServiceExecutor(ILogger logger)
{
_logger = logger;
}
public async Task ExecuteAsync(IMessageSender sender, TransportMessage message)
{
_logger.Debug("服务提供者接收到消息"); if (!message.IsInvokeMessage())
return; JsonRequest jsonRequest;
try
{
jsonRequest = message.GetContent<JsonRequest>();
}
catch (Exception exception)
{
_logger.Error("将接收到的消息反序列化成 TransportMessage<JsonRequest> 时发送了错误。", exception);
return;
} _logger.Debug("准备执行本地逻辑。"); var resultMessage = await LocalExecuteAsync(jsonRequest, message.Headers); //向客户端发送调用结果。
await SendRemoteInvokeResult(sender, message.Id, JsonConvert.DeserializeObject<JsonResponse>(resultMessage));
} private async Task<string> LocalExecuteAsync(JsonRequest jsonRequest,object headers)
{
return await JsonRpcProcessor.Process(JsonConvert.SerializeObject(jsonRequest), headers);
} private async Task SendRemoteInvokeResult(IMessageSender sender, string messageId, JsonResponse resultMessage)
{
try
{ _logger.Debug("准备发送响应消息。"); await sender.SendAndFlushAsync(TransportMessage.CreateInvokeResultMessage(messageId, resultMessage, new NameValueCollection()));
_logger.Debug("响应消息发送成功。");
}
catch (Exception exception)
{
_logger.Error("发送响应消息时候发生了异常。", exception);
}
}
}
这部分内容没有太多的说明,参见surging
企业级工作流解决方案(八)--微服务Tcp消息传输模型之服务端处理的更多相关文章
- 企业级工作流解决方案(七)--微服务Tcp消息传输模型之消息编解码
Tcp消息传输主要参照surging来做的,做了部分裁剪和改动,详细参见:https://github.com/dotnetcore/surging Json-rpc没有定义消息如何传输,因此,Jso ...
- 企业级工作流解决方案(九)--微服务Tcp消息传输模型之客户端处理
客户端启动 客户端启动主要做三件事情,1. 从配置文件读取服务调用配置,存储到全局对象中.2. 指定客户端编解码器工厂.3. 预连接,即预先建立与服务端的通信Chanel. [DependsOn(ty ...
- 企业级工作流解决方案(十四)--集成Abp和ng-alain--自动化脚本
对于.net方向,做过自动化的,应该没有人不熟悉msbuild吧,非常强大的代码编译工具,.net平台的编译工作都是交给他来完成的,包括.net core的命令,本质上都是调用msbuild来执行的 ...
- 企业级工作流解决方案(六)--微服务消息处理模型之与Abp集成
身份认证传递 对于Abp比较熟悉的朋友应该对他里面的用户身份认证比较熟悉,他是通过实现微软提供的权限认证方式实现的,用户登录身份信息存储在System.Security.Claims.ClaimsPr ...
- 企业级工作流解决方案(十五)--集成Abp和ng-alain--Abp其他改造
配置功能增强 Abp定义了各种配置接口,但是没有定义这些配置数据从哪里来,但是管理配置数据对于一个应用程序来说,是必不可少的一件事情. .net的配置数据管理,一般放在Web.config文件或者Ap ...
- 企业级工作流解决方案(十一)--集成Abp和ng-alain--权限系统服务
权限系统主要定义为管理员增删改查权限数据,直接读取数据库,权限系统服务主要定义为供其他系统调用的权限验证接口,定义为两个不同的微服务. 权限系统有一个特点,数据变动比较小,数据量本身并不是很大,访问量 ...
- 企业级工作流解决方案(十)--集成Abp和ng-alain--权限系统
权限系统 应用系统离不开权限控制,权限中心不一定能抽象出所有的业务场景,这里定义的权限系统不一定能够满足所有的场景,但应该可以满足多数的业务需求. Abp的zero项目也定义了权限相关的表,但里面很多 ...
- 企业级工作流解决方案(十三)--集成Abp和ng-alain--数据库读写分离
说到程序里面数据库管理,无非就是两件事情,一是数据库操作,对于数据库的操作,各种程序语言都有封装,也就是所谓的ORM框架,.net 方向一般用得比较多和就是.net framework和dapper, ...
- 企业级工作流解决方案(十二)--集成Abp和ng-alain--用户身份认证与权限验证
多租户 如果系统需要支持多租户,那么最好事先定义好多租户的存储部署方式,Abp提供了几种方式,根据需要选择,每一个用户身份认证与权限验证都需要完全的隔离 这里设计的权限数据全部存储在缓存中,每个租户单 ...
随机推荐
- ServletResponse使用介绍
ServletResponse为将响应发送到客户端的对象:Servlet 容器创建 ServletResponse 对象,并将它作为参数传递给Servlet的service 方法,如下图 : Http ...
- PowerShell查看历史记录
PowerShell的所有历史记录: Get-Content (Get-PSReadLineOption).HistorySavePath 顺手写了一个掉用的函数: function Get ...
- B. Two Fairs 解析(思維、DFS、組合)
Codeforce 1276 B. Two Fairs 解析(思維.DFS.組合) 今天我們來看看CF1276B 題目連結 題目 給一個連通圖,並給兩個點(\(a,b\)),求有多少點對使得:任一路徑 ...
- 【论文阅读】分布一致性算法Paxos 《The Part-Time Parliament》
论文原文.翻译稿.PPt:https://1drv.ms/u/s!Ak-jGl23kTuMimOZzV-MyLQUYmsN?e=DL1xHD
- 关于机器翻译评价指标BLEU(bilingual evaluation understudy)的直觉以及个人理解
最近我在做Natural Language Generating的项目,接触到了BLEU这个指标,虽然知道它衡量的是机器翻译的效果,也在一些文献的experiment的部分看到过该指标,但我实际上经常 ...
- 想买保时捷的运维李先生学Java性能之 垃圾收集器
前言 垃圾收集算法是内存回收的方法论:垃圾收集器是内存回收的具体实现.Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都有很大的差别,并且 ...
- pytorch 图像分类数据集(Fashion-MNIST)
import torch import torchvision import torchvision.transforms as transforms import matplotlib.pyplot ...
- 学习写简单Spring源码demo
最近在研究怎么实现简单的Spring的源码,通过注解的方式来实现对bean的加载管理. 首先先来看下我的工程结构: (1)spring-common:定义了常用的枚举常量,工具类(如FileUtils ...
- 使用AI技术获取图片文字与识别图像内容
获取图片文字 如何使用python获取图片文字呢? 关注公众号[轻松学编程]了解更多- 1.通过python的第三方库pytesseract获取 通过pip install pytesseract导入 ...
- Java中的(String args[])
1. DOS下运行 首先,String args[] 这个形式可以直接看出它就是一个字符串数组充当main函数形式参数,args是arguments的缩写,不是关键字(就是一个数组名),可以改但没必要 ...