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

上节中有谈到的是通信主机(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. Sting和Long类型转换

    java String 转 Long 两种方法区别Long.ValueOf("String")返回Long包装类型包装类型: Byte,Integer,Short,Long,Boo ...

  2. linux初学者-磁盘分区方式篇

    linux初学者-磁盘分区方式篇 一般的计算机都会采用mbr分区方式,这种分区方式只能够建立四个主分区,如果还需要或更多的分区,就需要将其中一个主分区建立成一个扩展分区,在里面建立逻辑分区,这些分区信 ...

  3. 【iOS】设置 rootViewController

    iOS 开发中,rootViewController 经常用到,示例代码如下: self.window = [[UIWindow alloc] initWithFrame:[UIScreen main ...

  4. 【Mac】解压文件夹中文乱码

    Mac 用的英文系统,发现下载含中文的文件后,解压为乱码,如图所示: 解决方法: 下载一个解压软件:"The Unarchiver" 安装后设置下,如图: 之后设置压缩文件的默认打 ...

  5. Python-默背单词

    ​ 数据库单词: 默认单词 单词说明 innodb 事务,主键,外键,tree,表行锁 myisam 主要以插入读取和插入操作 memory 所有数据保存在内存中 ACID 原子性,一致性,隔离性,持 ...

  6. Consul和Kong的实践(一)

    Consul和Kong的实践(一) 这一篇先介绍consul集群,以及consul和应用服务的结合使用,下一篇是和kong网关的结合. 一.Consul的集群安装 以其中一台机器为例: mkdir / ...

  7. JWT token 跨域认证

    JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案. session登录认证方案:用户从客户端传递用户名.密码等信息,服务端认证后将信息存储在session中,将sessio ...

  8. hdu 6397 Character Encoding (生成函数)

    Problem Description In computer science, a character is a letter, a digit, a punctuation mark or som ...

  9. 使用Arthas 获取Spring ApplicationContext还原问题现场

    ## 背景 最近来了个实习僧小弟,安排他实现对目标网站 连通性检测的小功能,简单讲就是将下边的shell 脚本换成Java 代码来实现 ``` 1#!/bin/bash 2URL="http ...

  10. SpringBoot入门及YML文件详解

    SpringBoot 简介 微框架,与 Spring4 一起诞生,基于约定.生来为了简化 spring 的配置 优点 可以快速的上手,整合了一些子项目(开源框架或者第三方开源库) 可以依赖很少的配置快 ...