• (八)分布式通信----主机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 = 1; i < 10000; i++)
                        {
                            var invokeMessage = new TransportMessage
                            {
                                Id = i.ToString(),
                                ContentType = "string",
                                Content = "你好啊,这是客户端发给服务端的消息"
                            };
                            try
                            {
                                var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 981);
                                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 = 981;
                    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));
                    });
            }
        }
  • 相关阅读:
    RedisHelper
    2010年:Socket实践问题求助解决一贴通
    React Hooks 父组件调用子组件的方法
    React Hooks 进入页面以后自动 focus 到某个输入框
    react hooks 太多的useState 显得很冗余,有没有什么规整的方法呢?
    react项目取消部分eslint检查
    使用useMemo优化性能
    react的useEffect 第二个参数
    如何使用 Postman Interceptor(可以拦截浏览器的请求到postman)
    react阻止事件冒泡
  • 原文地址:https://www.cnblogs.com/hongwei918/p/11415390.html
Copyright © 2020-2023  润新知