.NET Core中用于TCP服务器的IHostedService [英] IHostedService for tcp servers in .NET Core

查看:311
本文介绍了.NET Core中用于TCP服务器的IHostedService的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用asp.net核心作为与服务器交互的Web前端构建小型tcp服务器/守护程序。我发现IHostedService / BackgroundService似乎为将服务器和前端捆绑在一起提供了一种省力的选择。

I am trying to build a small tcp server/daemon with asp.net core as a web frontend to interact with the server. I have found IHostedService/BackgroundService which seems to provide a low effort alternative to bundle the server and the frontend together.

目前,代码基本上像这样(回显服务器)用于测试):

The code looks basically like this at the moment (echo server for testing purposes):

public class Netcat : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 8899);
        listener.Start();
        while(!stoppingToken.IsCancellationRequested)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            NetworkStream stream = client.GetStream();

            while (!stoppingToken.IsCancellationRequested)
            {
                byte[] data = new byte[1024];
                int read = await stream.ReadAsync(data, 0, 1024, stoppingToken);

                await stream.WriteAsync(data, 0, read, stoppingToken);
            }
        }
    }
}

像这样在Startup.cs中初始化:

And is initialized in Startup.cs like this:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHostedService<Netcat>();
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

Asp.Net核心应用程序和守护程序应如何使用一个通用模式

Is there a common pattern for how modern Asp.Net core applications and daemons should cooperate?

我将如何从Controller与正在运行的服务本身进行交互?

How would I interact with the running service itself from a Controller?

IHostedService是否甚至可用于此目的还是将Asp.Net前端与服务/服务器完全分离的更好方法,例如通过使用某种IPC机制将daemon和asp.net作为独立的进程运行?

Is IHostedService even usable for this purpose or is it a better way that fully decouples the Asp.Net frontend and the service/server, e.g. by running the daemon and asp.net as seperate processes with some sort of IPC mechanism?

推荐答案


现代Asp.Net核心应用程序和守护程序应该如何协作?

Is there a common pattern for how modern Asp.Net core applications and daemons should cooperate?

实际上,托管服务没有那么强大就目前而言。所以人们通常使用第三种产品。
但是,可以与托管服务和控制器进行通信。我将以您的代码为例来实现这些目标:

Actually , the hosted service is not that powerful for the present . So people usually use a third product . However , it's possible to communicate with hosted service and controller . I'll use your code as an example to achieve these goals :


  1. TcpServer 能够接收两个命令,以便我们可以从 TcpClient 切换托管服务的状态。

  2. <$的控制器c $ c> WebServer 可以间接(通过中介器)调用 TcpServer 的方法,并将其呈现为html

  1. The TcpServer is able to receive two commands so that we can switch the state of hosted service from a TcpClient.
  2. The controller of WebServer can invoke method of TcpServer indirectly (through a mediator ), and render it as html

与控制器耦合不是一个好主意托管服务。要从托管服务中调用方法,我们可以引入介体。中介者不过是充当单例的服务(因为它将由托管服务引用):

It's not a good idea to couple controller with hosted service . To invoke method from hosted service , we can introduce a Mediator . A mediator is no more than a service that serves as a singleton (because it will referenced by hosted service) :

public interface IMediator{
    event ExecHandler ExecHandler ; 
    string Exec1(string status);
    string Exec2(int status);
    // ...
}

public class Mediator: IMediator{

    public event ExecHandler ExecHandler ;
    public string Exec1(string status)
    {
        if(this.ExecHandler==null) 
            return null;
        return this.ExecHandler(status);
    }

    public string Exec2(int status)
    {
        throw new System.NotImplementedException();
    }
}

托管服务需要意识到<$的存在c $ c> IMediator 并以某种方式将其方法公开给 IMediator

A Hosted Service needs to realize the existence of IMediator and expose his method to IMediator in some way :

public class Netcat : BackgroundService
{
    private IMediator Mediator ;
    public Netcat(IMediator mediator){
        this.Mediator=mediator;
    }

    // method that you want to be invoke from somewhere else
    public string Hello(string status){
        return $"{status}:returned from service";
    }

    // method required by `BackgroundService`
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 8899);
        listener.Start();
        while(!stoppingToken.IsCancellationRequested)
        {
            // ...
        }
    }
}

为了允许从NetCat TcpServer 控制状态,我使其能够接收两个命令从客户端切换后台服务的状态:

To allow control the status from the NetCat TcpServer , I make it able to receive two commands from clients to switch the state of background service :

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 8899);
        listener.Start();
        while(!stoppingToken.IsCancellationRequested)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            Console.WriteLine("a new client connected");
            NetworkStream stream = client.GetStream();

            while (!stoppingToken.IsCancellationRequested)
            {
                byte[] data = new byte[1024];
                int read = await stream.ReadAsync(data, 0, 1024, stoppingToken);
                var cmd= Encoding.UTF8.GetString(data,0,read);
                Console.WriteLine($"[+] received : {cmd}");

                if(cmd=="attach") { 
                    this.Mediator.ExecHandler+=this.Hello;
                    Console.WriteLine($"[-] exec : attached");
                    continue;
                }
                if(cmd=="detach") {
                    Console.WriteLine($"[-] exec : detached");
                    this.Mediator.ExecHandler-=this.Hello;
                    continue;
                }

                await stream.WriteAsync(data, 0, read, stoppingToken);
                stream.Flush();
            }
        }
    }

如果要调用控制器内部后台服务的方法,只需将
注入 IMediator

If you want to invoke the method of background service within a controller, simply inject the IMediator :

public class HomeController : Controller
{
    private IMediator Mediator{ get; }

    public HomeController(IMediator mediator){
        this.Mediator= mediator;
    }

    public IActionResult About()
    {
        ViewData["Message"] = this.Mediator.Exec1("hello world from controller")??"nothing from hosted service";

        return View();
    }
}

这篇关于.NET Core中用于TCP服务器的IHostedService的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆