(八)分布式通信----主机Host
上节中有谈到的是通信主机(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的更多相关文章
- (七)分布式通信----Netty实现NIO通信
目录 1. 消息监听器 2. 指令执行器 3. 消息发送器 4. 客户端工厂 5. 序列化工具 6. 通信主机 项目文件结构图 通信主机: 1. 消息监听器(黄色框) 这部分由 Netty 实现,Ne ...
- 4.7 ROS分布式通信
4.7 ROS分布式通信 ROS是一个分布式计算环境.一个运行中的ROS系统可以包含分布在多台计算机上多个节点.根据系统的配置方式,任何节点可能随时需要与任何其他节点进行通信. 因此,ROS对网络配置 ...
- axis实现webservices分布式通信
分布式通信原理 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2ZsMjAxMjEzMTQ=/font/5a6L5L2T/fontsize/400/fil ...
- 10.axis实现webservices分布式通信
转自:https://www.aliyun.com/jiaocheng/310112.html 分布式通信原理 基本原理:stub和skeleton作为客户端和服务端传输的中介,stub和skelet ...
- virtual box设置网络,使用nat网络和仅主机(Host Only)网络进行连接
virtual box设置网络,使用nat网络和仅主机(Host Only)网络进行连接 前言 作为程序员难免要在本机电脑安装虚拟机,最近在用virtual box安装虚拟机的时候遇到了点问题. 对于 ...
- 分布式进阶(十八) 分布式缓存之Memcached
分布式缓存 分布式缓存出于如下考虑:首先是缓存本身的水平线性扩展问题,其次是缓存大并发下本身的性能问题,再次避免缓存的单点故障问题(多副本和副本一致性). 分布式缓存的核心技术包括首先是内存本身的管理 ...
- [Docker]——container和主机(host)之间的文件拷贝
1. 从 container 到 主机(host) 使用 docker cp 命令 docker cp <containerId>:/file/path/within/container ...
- 分布式通信框架RMI
1.RPC概念: Remote procedure call protocal,远程过程调用协议,一般用来实现部署在不同机器上的系统之间的方法调用, 使得程序能够像访问本地系统资源一样,通过网络传输去 ...
- 分布式通信-tcp/ip socket
Socket通讯的过程 Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受) ...
随机推荐
- Redis(三)--- Redis的五大数据类型的底层实现
1.简介 Redis的五大数据类型也称五大数据对象:前面介绍过6大数据结构,Redis并没有直接使用这些结构来实现键值对数据库,而是使用这些结构构建了一个对象系统redisObject:这个对象系统包 ...
- ALLOT流控设备SSG
Allot AC 系列产品EOL的通知如下. 该产品于2021年3月31日EOL. 替代的产品系列为SG/SSG系列. Allot Secure Service Gateway(SSG)应用程序和用户 ...
- gawk(awk)的用法案例
gawk(awk)的用法案例 本文首先简单介绍一个gawk和awk的区别,然后是一点基本使用流程,最后是自己做的一个分析数据文件的脚本代码,供大家参考.另外想了解基本流程的入门知识的可以下载附件pdf ...
- 技术派-不用sqrt手工计算平方根
题目:任意长度数串,不使用sqrt函数,手工计算平方根? 要求只准用加/减/乘/除四则运算,不准使用power/sqrt等函数. 算法如下: 1.以小数点为中心往两边每2位分隔为一组: 2.然 ...
- springBoot综合开发
作者:纯洁的微笑出处:www.ityouknow.com 版权所有,欢迎保留原文链接进行转载:) 上篇文章介绍了Spring boot初级教程:spring boot(一):入门篇,方便大家快速入门. ...
- Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及区别
本篇博客主要讲解List接口的三个实现类ArrayList.LinkedList.Vector的使用方法以及三者之间的区别. 1. ArrayList使用 ArrayList是List接口最常用的实现 ...
- 【Android】Field requires API level 4 (current min is 1): android.os.Build.VERSION#SDK_INT
刚遇到了这个问题: Field requires API level 4 (current min is 1): android.os.Build.VERSION#SDK_INT 解决方法: 修改 A ...
- 【iOS】Receiver type 'XXX' for instance message is a forward declaration
今天遇到这个错误.刚开始字体太大,没显示全,后来调小字体之后看到了完整提示信息: 之后就忽然想起没引入相关的类,添加 #import "RDVTabBarItem.h" 就行了.
- Js面向对象构造函数继承
构造函数继承 <!-- 创建构造函数 --> function Animal(){ this.species= '动物'; } function Dog(name,color){ this ...
- Netty服务端启动过程相关源码分析
1.Netty 是怎么创建服务端Channel的呢? 我们在使用ServerBootstrap.bind(端口)方法时,最终调用其父类AbstractBootstrap中的doBind方法,相关源码如 ...