简体   繁体   English

如何将ConnectionHandler切换到UDP

[英]How to switch a ConnectionHandler to UDP

My ASP.Net Core application provides a TCP listener, implemented with a custom ConnectionHandler , to receive binary data from another process (let's call it Datasource ) on another host. 我的ASP.Net Core应用程序提供了一个TCP侦听器,该侦听器使用自定义ConnectionHandler实施,以从另一个主机上的另一个进程(称为Datasource )接收二进制数据。 This data is then sent to the browser through a WebSocket (called DataSink in the code). 然后,这些数据通过WebSocket(在代码中称为DataSink )发送到浏览器。

Since the process Datasource has changed from a single TCP connection to UDP datagrams, I need to adapt (its internals are out of my reach). 由于Datasource的过程已从单个TCP连接更改为UDP数据报,因此我需要进行调整(其内部无法访问)。

How can I switch the current implementation to an UDP listener? 如何将当前实现切换到UDP侦听器? Is there a canonical way how this is done with ASP.Net Core? 有没有使用ASP.Net Core的规范方法?

public class MySpecialConnectionHandler : ConnectionHandler
{
    private readonly IMyDataSink DataSink;

    public MySpecialConnectionHandler(IMyDataSink dataSink)
    {
        DataSink = dataSink;
    }

    public override async Task OnConnectedAsync(ConnectionContext context)
    {
        TransportConnection connection = context as TransportConnection;

        Console.WriteLine("new connection: " + connection.RemoteAddress + ":" + connection.RemotePort);

        while (true)
        {
            var result = await connection.Transport.Input.ReadAsync().ConfigureAwait(false);
            var buffer = result.Buffer;

            foreach (var segment in buffer)
            {
                await DataSink.RelayData(segment.Span.ToArray()).ConfigureAwait(false);
            }

            if (result.IsCompleted)
            {
                break;
            }

            connection.Transport.Input.AdvanceTo(buffer.End);
        }

        Console.WriteLine(connection.ConnectionId + " disconnected");
    }
}

The UDP listener must be available while the ASP.Net Core application is running. 在ASP.Net Core应用程序运行时,UDP侦听器必须可用。

EDIT: 编辑:

Order and reliability of the datagram transmission is not that important (perhaps not at all), since the transmitted data is a MPEG1-stream multiplexed into MPEG-TS. 数据报传输的顺序和可靠性不是那么重要(也许一点也不重要),因为传输的数据是复用到MPEG-TS中的MPEG1流。 The data source is on the first host, the ASP.Net Core application is on a second host and the receiver / consumer is a third host. 数据源在第一台主机上,ASP.Net Core应用程序在第二台主机上,接收器/使用者在第三台主机上。 The host creating the stream and the receiving process on the third host are in separate networks. 创建流的主机和第三台主机上的接收过程位于单独的网络中。 The ASP.Net Core application acts as a relay. ASP.Net Core应用程序充当中继。 The sender is sending all time, but does not care about whether the data is received or not. 发件人一直在发送,但并不关心是否已接收到数据。

EDIT 2: 编辑2:

The main problem right now is where to put the UdpClient. 现在的主要问题是将UdpClient放在哪里。 The previous implementation (back when we used TCP) configured the Kestrel server for additional TCP listening and used the already presented ConnectionHandler : 先前的实现(使用TCP时返回)将Kestrel服务器配置为进行其他TCP侦听,并使用了已经提供的ConnectionHandler

return WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .ConfigureKestrel((_, options) =>
    {
        // HTTP
        options.Listen(networkInterface, httpPort);

        // HTTPS
        options.Listen(networkInterface, httpsPort, builder => builder.UseHttps());

        // stream sink
        options.Listen(streamInterface, streamPort, builder => builder.UseConnectionHandler<MySpecialConnectionHandler >());
    }); 

The ConnectionHandler accepts the incoming TCP connection and then forwards the streaming data to a number of connected WebSockets. ConnectionHandler接受传入的TCP连接,然后将流数据转发到许多已连接的WebSocket。 Since this is not usable with UDP datagrams, I need to place the UdpClient somewhere where it continuously (ie while(true) ) receives datagrams and forwards them to the WebSockets. 由于这不适用于UDP数据报,因此我需要将UdpClient放置在连续的位置(即while(true) )接收数据报并将其转发到WebSockets。 My problem is that I don't know where to put it, run the background thread and have the communication span threads without having any problems with this inter-thread data flow (like race conditions). 我的问题是,我不知道将它放在哪里,运行后台线程并没有通信跨线程,而对此线程间数据流(例如竞争条件)没有任何问题。

So, to conclude this: 因此,得出以下结论:

We used a combination of a BackgroundWorker with an UdpClient . 我们将BackgroundWorkerUdpClient结合使用。 The BackgroundWorker is only instantiated when there is at least one receiver: 仅当至少有一个接收器时才实例化BackgroundWorker

StreamReceiver = new BackgroundWorker();
StreamReceiver.DoWork += ReceiveStream;
StreamReceiver.RunWorkerAsync();

ReceiveStream is a private method that establishes the UdpClient and then waits for incoming data that needs to be relayed. ReceiveStream是建立UdpClient的私有方法,然后等待需要中继的传入数据。

private async void ReceiveStream(object sender, DoWorkEventArgs e)
{
    // DataSinkPort is a const int
    UdpClient datasource = new UdpClient(_DataSinkPort);

    while (true)
    {
        var rec = await datasource.ReceiveAsync();
        await RelayData(rec.Buffer);

        if (_CancellationToken.IsCancellationRequested)
        {
            return;
        }
    }
}

The method RelayData just uses the outgoing TCP connection of each subscribed receiver. RelayData方法仅使用每个订阅接收者的传出TCP连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM