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

上节中有谈到的是通信主机(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. to_string()函数(C++)

    to_string函数,这是C++11新增的,使用非常方便,简单查了下:C++11标准增加了全局函数std::to_string 函数原型:string to_string (int val);str ...

  2. Linux 下实践 VxLAN

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫. 来源:ht ...

  3. TCP三次握手和断开四次挥手

    TCP三次握手 1主机A发送消息请求与主机B连接 2主机B回复消息同意与主机A连接 3主机A确认主机B的同意连接,并建立连接 TCP的四次挥手 1客户端发送FIN到服务器,请求关闭与服务器的连接(意思 ...

  4. Djangou中使用cookie和session

    一.会话跟踪 我们先需要了解是什么是会话!可以把会话理解为客户端与服务器之间的一次会话,在一次会话中可能会包含多次请求和响应,例如你给10086打个电话,你就是客户端,而10086服务人员就是服务器, ...

  5. CentOS 配置阿里云 NTP 服务

    NTP 是网络时间协议(Network Time Protocol),NTP 服务能保证服务器的本地时间与标准时间同步. ▶ 配置时区信息 1.删除系统里的当地时间链接 sudo rm /etc/lo ...

  6. webapck小知识点1

    全局安装webpack webpack-cli npm install webapck webpack-cli -g 卸载全局安装的webpack webpack-cli npm unistall w ...

  7. CSS3 filter 模糊滤镜的应用

    CSS3 filter 模糊滤镜的应用   在segmentfault上回答过的一个问题,如何将网页CSS背景图高斯模糊且全屏显示当时没有深入了解,只觉得滤镜应该只是应用于图片上的.而且各大网站的de ...

  8. .Net异步编程详解入门

    前言 今天周五,早上起床晚了.赶着挤公交上班.但是目前眼前有这么几件事情.刷牙洗脸.泡牛奶.煎蛋.在同步编程眼中.先刷牙洗脸,然后烧水泡牛奶.再煎蛋,最后喝牛奶吃蛋.毫无疑问,在时间紧促的当下.它完了 ...

  9. .xxx.sh脚本无法启动,原来都是特殊字符搞的鬼?

    今天遇到个趣的问题,linux上springboot启动,连接达梦数据库报错. 解决思路: 1)是不是数据库本身有问题,客户端登录没问题. 2)排查是不是war包问题,本地连接数据库,没问题. 3)是 ...

  10. caddy & grpc(3) 为 caddy 添加一个 反向代理插件

    caddy-grpc 为 caddy 添加一个 反向代理插件 项目地址:https://github.com/yhyddr/caddy-grpc 前言 上一次我们学习了如何在 Caddy 中扩展自己想 ...