==>>点击查看本系列文章目录

上节中有谈到的是通信主机(TransportHost),本节中主机(ServiceHost)负责管理服务的生命周期。

项目中将两个主机拆分开,实现不同的功能:

通信主机:用于启动通信监听端口;

生命周期管理的主机:负责模块功能的依赖注入,管理生命周期。

先看一下启动服务端主机和客户端主机后完成通信的效果图:

文件结构如下:

ServiceHost 主机由ServiceHostBuilder来构建。

过程如下:

先看调用图:

1.Program中Main() 调用 ServiceHostBuilder 的方法:MapServices、RegisterServices、ConfigureServices、Configure

  分别将委托填充到 List<Action<IContainer>>、List<Action<ContainerBuilder>>、List<Action<IServiceCollection>>、List<Action<IConfigurationBuilder>> 类型的容器中。

  其中 IContainer、ContainerBuilder 是 Autofac中的容器,IServiceCollection、IConfigurationBuilder 是 Microsoft中的容器。

2. Program中Main() 调用 ServiceHostBuilder 的方法 UseStartup<Startup>()  ,Startup 必须实现 IStartup,完成Startup 的单例注入(微软中的 Startup 可以不实现 IStartup ,但是必须使用方法ConfigureServices、Configure)

3. Program中Main() 调用 ServiceHostBuilder 的方法 Build()

  (1)回调容器 List<Action<IContainer>>、List<Action<ContainerBuilder>>、List<Action<IServiceCollection>>、List<Action<IConfigurationBuilder>> 中的委托。

      容器生成过程: ConfigureServices   ---》  List<Action<IServiceCollection>>      ---》  IServiceCollection

            Configure      ---》  List<Action<IConfigurationBuilder>>      ---》  IConfigurationBuilder

            IServiceCollection + IConfigurationBuilder  ---》  IServiceCollection   ---》  ServiceProvider

            RegisterServices     ---》  List<Action<ContainerBuilder>>       ---》  ContainerBuilder

            ContainerBuilder + IServiceCollection         ---》  ContainerBuilder

            MapServices      ---》  List<Action<IContainer>>

  (2)将上面红色字体的对象通过构造函数传给new 的 ServiceHost 对象。

  (3)调用ServiceHost .Initialize(),  该方法中执行如下过程

    a. 用ServiceProvider 解析出 Startup 对象

    b. 回调Startup的 IContainer ConfigureServices(ContainerBuilder builder) , 返回构建好的容器 IContainer

    c. 回调Startup的 void Configure(IContainer app) , IContainer中注入其它功能

  (4)将包含IContainer容器的ServiceHost 对象返回

4. ServiceHost.Run(), 回调主机中一直未执行的容器委托 List<Action<IContainer>>

总结一下,整个过程就是将原来的四个委托的容器最后合并成一个 IContainer 容器。

解析容器中的服务,可以用 :

IContainer _container;
IDemoService service = _container.Resolve<IDemoService>(); 

服务端和客户端启动:

代码:

我们先看客户端和服务端代码:

服务端:

namespace Leo.ServiceLaunch.Server
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Server, Hello World!"); var host = new ServiceHostBuilder()
.RegisterServices(builder =>
{
builder.RegisterType<MessagePackTransportMessageCodecFactory>().As<ITransportMessageCodecFactory>().SingleInstance();
builder.RegisterType(typeof(HttpServiceExecutor)).As(typeof(IServiceExecutor)).Named<IServiceExecutor>("tcp").SingleInstance();
builder.Register(provider =>
{
return new DotNettyServerMessageListener(provider.Resolve<ILogger<DotNettyServerMessageListener>>(),
provider.Resolve<ITransportMessageCodecFactory>());
}).SingleInstance();
builder.Register(provider =>
{
var serviceExecutor = provider.ResolveKeyed<IServiceExecutor>("tcp");
var messageListener = provider.Resolve<DotNettyServerMessageListener>();
return new DotNettyTransportHost(async endPoint =>
{
await messageListener.StartAsync(endPoint);
return messageListener;
}, serviceExecutor);
}).As<ITransportHost>();
})
.UseServer() // 指定监听的端口
.UseStartup<Startup>()
.Build(); using (host.Run())
{
Console.WriteLine($"服务端启动成功,{DateTime.Now}。");
} Console.ReadLine();
} }
}
namespace Leo.ServiceLaunch.Server
{
class Startup : IStartup
{
public IContainer ConfigureServices(ContainerBuilder builder)
{
return builder.Build();
} public void Configure(IContainer app)
{ }
}
}

客户端:

namespace Leo.ServiceLaunch.Client
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Client, Hello World!"); var host = new ServiceHostBuilder()
.RegisterServices(builder =>
{
builder.RegisterType<MessagePackTransportMessageCodecFactory>().As<ITransportMessageCodecFactory>().SingleInstance();
builder.Register(provider =>
{
IServiceExecutor serviceExecutor = null;
if (provider.IsRegistered(typeof(IServiceExecutor))) // 没有注册客户端接收消息执行器,因此一直为空
serviceExecutor = provider.Resolve<IServiceExecutor>();
return new DotNettyTransportClientFactory(provider.Resolve<ITransportMessageCodecFactory>(),
provider.Resolve<ILogger<DotNettyTransportClientFactory>>(),
serviceExecutor);
}).As(typeof(ITransportClientFactory)).SingleInstance();
})
.UseStartup<Startup>()
.Build(); using (host.Run())
{
Startup.Test();
}
Console.ReadLine();
}
}
}
namespace Leo.ServiceLaunch.Client
{
class Startup : IStartup
{
private static IContainer _container;
public void Configure(IContainer app)
{
} public IContainer ConfigureServices(ContainerBuilder builder)
{
_container = builder.Build();
return _container;
} internal static void Test()
{
Task.Run(async () =>
{
do
{
Console.WriteLine("正在循环 1万次发送消息....."); //1w次调用
var watch = Stopwatch.StartNew();
for (var i = ; i < ; i++)
{
var invokeMessage = new TransportMessage
{
Id = i.ToString(),
ContentType = "string",
Content = "你好啊,这是客户端发给服务端的消息"
};
try
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), );
ITransportClientFactory transportClientFactory = _container.Resolve<ITransportClientFactory>();
var client = await transportClientFactory.CreateClientAsync(endPoint);
await client.SendAsync(invokeMessage);
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString(), $"发起请求中发生了错误,服务Id:{invokeMessage.Id}。");
throw;
}
}
watch.Stop();
Console.WriteLine($"1万次发送结束,执行时间:{watch.ElapsedMilliseconds}ms");
Console.WriteLine("Press any key to continue, q to exit the loop...");
var key = Console.ReadLine();
if (key.ToLower() == "q")
break;
} while (true);
}).Wait();
}
}
}

主机:

IServiceHost:

    public interface IServiceHost : IDisposable
{
IDisposable Run(); IContainer Initialize();
}

IServiceHostBuilder:

    public interface IServiceHostBuilder
{
IServiceHost Build(); IServiceHostBuilder RegisterServices(Action<ContainerBuilder> builder); IServiceHostBuilder ConfigureServices(Action<IServiceCollection> configureServices); IServiceHostBuilder Configure(Action<IConfigurationBuilder> builder); IServiceHostBuilder MapServices(Action<IContainer> mapper);
}

ServiceHost:

public class ServiceHost : IServiceHost
{
private readonly ContainerBuilder _builder;
private IStartup _startup;
private IContainer _applicationServices;
private readonly IServiceProvider _hostingServiceProvider;
private readonly List<Action<IContainer>> _mapServicesDelegates; public ServiceHost(ContainerBuilder builder,
IServiceProvider hostingServiceProvider,
List<Action<IContainer>> mapServicesDelegate)
{
_builder = builder;
_hostingServiceProvider = hostingServiceProvider;
_mapServicesDelegates = mapServicesDelegate;
} public IContainer Initialize()
{
if (_applicationServices == null)
{
try
{
if (_applicationServices == null)
{
if (_startup == null)
{
// 解析出 Startup
_startup = _hostingServiceProvider.GetRequiredService<IStartup>();
}
//回调Startup中的 ConfigureServices,
_applicationServices = _startup.ConfigureServices(_builder);
}
if (_applicationServices == null)
_applicationServices = _builder.Build();
Action<IContainer> configure = _startup.Configure;
configure(_applicationServices);
}
catch (Exception ex)
{
Console.Out.WriteLine("应用程序启动异常: " + ex.ToString());
throw;
}
}
return _applicationServices;
} public IDisposable Run()
{
RunAsync().GetAwaiter().GetResult();
return this;
} public async Task RunAsync()
{
if (_applicationServices != null)
MapperServices(_applicationServices);
} private void MapperServices(IContainer mapper)
{
foreach (var mapServices in _mapServicesDelegates)
{
mapServices(mapper);
}
} public void Dispose()
{
(_hostingServiceProvider as IDisposable)?.Dispose();
}
}

ServiceHostBuilder:

public class ServiceHostBuilder : IServiceHostBuilder
{
private readonly List<Action<IServiceCollection>> _configureServicesDelegates;
private readonly List<Action<ContainerBuilder>> _registerServicesDelegates;
private readonly List<Action<IConfigurationBuilder>> _configureDelegates;
private readonly List<Action<IContainer>> _mapServicesDelegates; public ServiceHostBuilder()
{
_configureServicesDelegates = new List<Action<IServiceCollection>>();
_registerServicesDelegates = new List<Action<ContainerBuilder>>();
_configureDelegates = new List<Action<IConfigurationBuilder>>();
_mapServicesDelegates = new List<Action<IContainer>>(); } public IServiceHost Build()
{
#region Microsoft原生的容器
//执行 IServiceCollection 类型的委托
var services = BuildCommonServices();
//执行 IConfigurationBuilder 类型的委托
var config = Configure();
//日志注入到 IServiceCollection
services.AddLogging();
//IConfigurationBuilder 注入到 IServiceCollection
services.AddSingleton(typeof(IConfigurationBuilder), config);
//用 IServiceCollection 生成 ServiceProvider 服务提供器
var hostingServiceProvider = services.BuildServiceProvider();
#endregion #region Autofac的容器
//执行 ContainerBuilder 类型的委托
var hostingServices = RegisterServices();
#endregion //将 IServiceCollection 填充到 Autofac 的 ContainerBuilder 构建器中
hostingServices.Populate(services); //把Autofac的ContainerBuild的容器构建器、Microsoft的ServiceProvider服务提供器、已有的IContainer容器的委托 都放入主机中
var host = new ServiceHost(hostingServices, hostingServiceProvider, _mapServicesDelegates);
//主机初始化以后返回的是IContainer容器
var container = host.Initialize();
return host;
} public IServiceHostBuilder MapServices(Action<IContainer> mapper)
{
if (mapper == null)
{
throw new ArgumentNullException(nameof(mapper));
}
_mapServicesDelegates.Add(mapper);
return this;
} public IServiceHostBuilder RegisterServices(Action<ContainerBuilder> builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
_registerServicesDelegates.Add(builder);
return this;
} public IServiceHostBuilder ConfigureServices(Action<IServiceCollection> configureServices)
{
if (configureServices == null)
{
throw new ArgumentNullException(nameof(configureServices));
}
_configureServicesDelegates.Add(configureServices);
return this;
} public IServiceHostBuilder Configure(Action<IConfigurationBuilder> builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
_configureDelegates.Add(builder);
return this;
} private IServiceCollection BuildCommonServices()
{
var services = new ServiceCollection();
foreach (var configureServices in _configureServicesDelegates)
{
configureServices(services);
}
return services;
} private IConfigurationBuilder Configure()
{
//var config = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory);
var config = new ConfigurationBuilder();
foreach (var configure in _configureDelegates)
{
configure(config);
}
return config;
} private ContainerBuilder RegisterServices()
{
var hostingServices = new ContainerBuilder();
foreach (var registerServices in _registerServicesDelegates)
{
registerServices(hostingServices);
}
return hostingServices;
}
}

IStartup:

    public interface IStartup
{
IContainer ConfigureServices(ContainerBuilder builder); void Configure(IContainer app);
}

ServerExtensions:

    public static class ServerExtensions
{
public static IServiceHostBuilder UseServer(this IServiceHostBuilder hostBuilder)
{
return hostBuilder.MapServices(async mapper =>
{
int _port = ;
string _ip = "127.0.0.1"; Console.WriteLine($"准备启动服务主机,监听地址:{_ip}:{_port}。");
var transportHosts = mapper.Resolve<IList<ITransportHost>>();
Task.Factory.StartNew(async () =>
{
foreach (var transportHost in transportHosts)
await transportHost.StartAsync(_ip, _port);
}).Wait();
});
} public static IServiceHostBuilder UseStartup<TStartup>(this IServiceHostBuilder hostBuilder) where TStartup : IStartup
{
return hostBuilder
.ConfigureServices(services =>
{
services.AddSingleton(typeof(IStartup), typeof(TStartup));
});
}
}

(八)分布式通信----主机Host的更多相关文章

  1. (七)分布式通信----Netty实现NIO通信

    目录 1. 消息监听器 2. 指令执行器 3. 消息发送器 4. 客户端工厂 5. 序列化工具 6. 通信主机 项目文件结构图 通信主机: 1. 消息监听器(黄色框) 这部分由 Netty 实现,Ne ...

  2. 4.7 ROS分布式通信

    4.7 ROS分布式通信 ROS是一个分布式计算环境.一个运行中的ROS系统可以包含分布在多台计算机上多个节点.根据系统的配置方式,任何节点可能随时需要与任何其他节点进行通信. 因此,ROS对网络配置 ...

  3. axis实现webservices分布式通信

    分布式通信原理 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2ZsMjAxMjEzMTQ=/font/5a6L5L2T/fontsize/400/fil ...

  4. 10.axis实现webservices分布式通信

    转自:https://www.aliyun.com/jiaocheng/310112.html 分布式通信原理 基本原理:stub和skeleton作为客户端和服务端传输的中介,stub和skelet ...

  5. virtual box设置网络,使用nat网络和仅主机(Host Only)网络进行连接

    virtual box设置网络,使用nat网络和仅主机(Host Only)网络进行连接 前言 作为程序员难免要在本机电脑安装虚拟机,最近在用virtual box安装虚拟机的时候遇到了点问题. 对于 ...

  6. 分布式进阶(十八) 分布式缓存之Memcached

    分布式缓存 分布式缓存出于如下考虑:首先是缓存本身的水平线性扩展问题,其次是缓存大并发下本身的性能问题,再次避免缓存的单点故障问题(多副本和副本一致性). 分布式缓存的核心技术包括首先是内存本身的管理 ...

  7. [Docker]——container和主机(host)之间的文件拷贝

    1. 从 container 到 主机(host) 使用 docker cp 命令 docker cp <containerId>:/file/path/within/container ...

  8. 分布式通信框架RMI

    1.RPC概念: Remote procedure call protocal,远程过程调用协议,一般用来实现部署在不同机器上的系统之间的方法调用, 使得程序能够像访问本地系统资源一样,通过网络传输去 ...

  9. 分布式通信-tcp/ip socket

    Socket通讯的过程 Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受) ...

随机推荐

  1. Android App安装包瘦身计划

    Android App安装包瘦身计划 Android App安装包体积优化: 理由, 指标和可以采用的方法. 本文内容归纳如下图: 为什么要安装包瘦身 安装包需要瘦身吗? 不需要吗? 安装包要瘦身的主 ...

  2. spark 源码分析之七--Spark RPC剖析之RpcEndPoint和RpcEndPointRef剖析

    RpcEndpoint 文档对RpcEndpoint的解释:An end point for the RPC that defines what functions to trigger given ...

  3. React躬行记(11)——Redux基础

    Redux是一个可预测的状态容器,不但融合了函数式编程思想,还严格遵循了单向数据流的理念.Redux继承了Flux的架构思想,并在此基础上进行了精简.优化和扩展,力求用最少的API完成最主要的功能,它 ...

  4. 私有网络(VPC)概述

    1 什么是私有网络(VPC) 私有网络是一块可用户自定义的网络空间,您可以在私有网络内部署云主机.负载均衡.数据库.Nosql快存储等云服务资源.您可自由划分网段.制定路由策略.私有网络可以配置公网网 ...

  5. 聊一聊Java的枚举enum

    一. 什么是枚举 枚举是一种数据类型,具有集合的一些特点,可以存放多个元素,但存储对象有限且固定,枚举也有比较常见的使用场景,如我们需要表达性别(男.女),颜色(红.黄.蓝),星期(星期一.星期二.. ...

  6. C# 二维码的生成

    nuget 搜索qrcodenet,然后选择下载gma.qrcodenet public partial class Form1 : Form { public Form1() { Initializ ...

  7. 使用f12定位bug

    为什么找到网站中的bug后还要去分析它到底是属于前端bug还是后端bug 三个原因: 1.在一些公司,一个系统可能是由前端团队和后端团队共同开发出来的,因此在分配bug的时候,不同模块的bug一般都会 ...

  8. Codeforces Round #192 (Div. 2) (329A)C.Purification

    题意: 在一个正常的点可以净化该行该列的所有细胞,判断是否可以净化所有的细胞,并且输出所选的点. 思路: 如果可以的话,一定会选n个点. 先判断每一行是否有正常细胞,然后判断每一列是否有,如果都没有肯 ...

  9. HelloDjango 系列教程:博客从“裸奔”到“有皮肤”

    文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 在此之前我们已经编写了博客的首页视图,并且配置了 URL 和模板,让 django 能够正确地处理 HTTP 请求并返回合适的 ...

  10. (一)Mybatis基本配置,Statement方式,动态代理增删改查

    首先明白Mybatis是干什么的,之前使用jdbc操作数据库时候要写很多语句,获取光标,连接,获取具体对象进行相应操作,代码过于繁琐,所以现在有了Mybatis,它将这个操作整合在了一起,你不需要关心 ...