Asp.net core 在ASP.NET Core中保持流连接的活动状态

Asp.net core 在ASP.NET Core中保持流连接的活动状态,asp.net-core,video-streaming,asp.net-core-mvc,asp.net-core-webapi,Asp.net Core,Video Streaming,Asp.net Core Mvc,Asp.net Core Webapi,我正在制作一个基于ASP.NET内核的小型web应用程序。我的应用程序是通过服务将视频从客户端流到客户端 我关注了这个帖子: 我已经成功地实现了教程的应用程序,但是,这是用于从服务器到客户端的流式视频 我现在想做的是: 客户端注册到流媒体服务。(使用视频或音频标签) 服务接收客户端提交的数据(通过邮递员提交) 服务将数据广播到其每个注册的客户端 以下是我实施的内容: (Index.cshtml) 流化服务 public class StreamingService: IStreamin

我正在制作一个基于ASP.NET内核的小型web应用程序。我的应用程序是通过服务将视频从客户端流到客户端

我关注了这个帖子:

我已经成功地实现了教程的应用程序,但是,这是用于从服务器到客户端的流式视频

我现在想做的是:

  • 客户端注册到流媒体服务。(使用视频或音频标签)
  • 服务接收客户端提交的数据(通过邮递员提交)
  • 服务将数据广播到其每个注册的客户端
以下是我实施的内容:

(Index.cshtml)


流化服务

public class StreamingService: IStreamingService
{
    public IList<Stream> Connections {get;set;}

    public StreamingService()
    {
        Connections = new List<Stream>();
    }

    public byte[] AnalyzeStream(Stream stream)
    {
        long originalPosititon = 0;
        if (stream.CanSeek)
        {
            originalPosititon = stream.Position;
            stream.Position = 0;
        }

        try
        {
            var readBuffer = new byte[4096];
            int bytesReader;

            while ((byteRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
            {
                totalBytesRead += byteRead;

                if (totalBytesRead == readBuffer.Length)
                {
                    var nextByte = stream.ReadByte();
                    if (nextByte != -1)
                    {
                        var temp = new byte[readBuffer * 2];
                        Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                        Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                        readBuffer = temp;
                        totalBytesRead++;
                    }
                }
            }

            var buffer = readBuffer;
            if (readBuffer.Length != totalBytesRead)
            {
                buffer = new byte[totalBytesRead];
                Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
            }

            return buffer;
        }
        finally
        {
            if (stream.CanSeek)
                stream.Position = originalPosititon;
        }
    }
}
公共类StreamingService:IsStreamingService
{
公共IList连接{get;set;}
公共流化服务()
{
连接=新列表();
}
公共字节[]分析流(流)
{
长原始位置=0;
if(stream.CanSeek)
{
原始位置=流位置;
流位置=0;
}
尝试
{
var readBuffer=新字节[4096];
int字节读取器;
而((byteRead=stream.Read(readBuffer,totalBytesRead,readBuffer.Length-totalBytesRead))>0)
{
totalBytesRead+=字节数;
if(totalBytesRead==readBuffer.Length)
{
var nextByte=stream.ReadByte();
如果(下一字节!=-1)
{
var temp=新字节[readBuffer*2];
块复制(readBuffer,0,temp,0,readBuffer.Length);
Buffer.SetByte(临时,totalBytesRead,(字节)nextByte);
readBuffer=temp;
totalBytesRead++;
}
}
}
var buffer=readBuffer;
if(readBuffer.Length!=totalBytesRead)
{
缓冲区=新字节[totalBytesRead];
块复制(readBuffer,0,Buffer,0,totalBytesRead);
}
返回缓冲区;
}
最后
{
if(stream.CanSeek)
流位置=原始位置;
}
}
}
视频控制器

public class VideoController: Controller
{
    private readonly IStreamingService _streamingService;

    private readonly IHostingEnvironment _hostingEnvironment;

    public VideoController(IStreamingService streamingService, IHostingEnvironment hostingEnvironment)
    {
        _streamingService = streamingService;
        _hostingEnvironment = hostingEnvironment;
    }

    [HttpGet("initiate")]
    public IActionResult Initiate()
    {
        _streamingService.Connections.Add(Response.Body);
    }

    [HttpPost("broadcast")]
    public async Task<IActionResult> Broadcast()
    {
        // Retrieve data submitted from POSTMAN.
        var data = _streamingService.AnalyzeStream(Request.Body);

        foreach (var stream in _streamingService.Connections)
        {
            try
            {
                await stream.WriteAsync(data, 0, data.Length);
            }
            catch (Exception exception)
            {
                stream.Dispose();
                _streamingService.Connections.Remove(stream);
            }
        }
    }
}
公共类视频控制器:控制器
{
private readonly IStreamingService(私有只读IStreamingService);
私有只读IHostingEnvironment\u hostingEnvironment;
公共视频控制器(IStreamingService streamingService,IHostingEnvironment hostingEnvironment)
{
_streamingService=streamingService;
_hostingEnvironment=hostingEnvironment;
}
[HttpGet(“启动”)]
公共IActionResult Initiate()
{
_streamingService.Connections.Add(Response.Body);
}
[HttpPost(“广播”)]
公共异步任务广播()
{
//检索从邮递员提交的数据。
var data=_streamingService.AnalyzeStream(Request.Body);
foreach(在_streamingService.Connections中的变量流)
{
尝试
{
wait stream.WriteAsync(数据,0,数据.长度);
}
捕获(异常)
{
stream.Dispose();
_streamingService.Connections.Remove(流);
}
}
}
}
当我通过api/视频/广播从邮递员那里发送数据时。对于循环运行,我得到一个异常,表示流已被释放

我的问题是:

  • 如何使流保持活动状态以进行流式处理?
(在api/video/initiate中创建的流保持活动状态,当客户端调用api/video/broadcast时,所有启动的流将更新其日期,而不进行处理)


谢谢,

将流保留在缓存中是一种选择吗

你可以阅读更多关于它的内容。最简单的方法是将缓存服务添加到依赖项注入容器中,并通过VideoController中的构造函数注入请求的具体实现(正如您在IStreamingService和IHostingEnvironment中所做的那样)

只需将流添加到缓存中,并在下次命中api/视频/广播时使用缓存流


但要注意,如果您在webfarm上或托管在云中,建议使用Redis缓存之类的缓存,否则您的缓存可能会意外失效。我使用的例子,这是伟大的作品

但当我访问该流时,它将被释放。我可以使用IMemoryCache保持客户端和服务器之间的连接吗?我的错,我应该先问你一些问题。如何注册IStreamingService?哪一辈子?瞬态、作用域还是单例?我使用IStreamingService作为单例(services.addSingleton())Hi@Redplane,您找到解决方案了吗?我也有同样的问题。
public class VideoController: Controller
{
    private readonly IStreamingService _streamingService;

    private readonly IHostingEnvironment _hostingEnvironment;

    public VideoController(IStreamingService streamingService, IHostingEnvironment hostingEnvironment)
    {
        _streamingService = streamingService;
        _hostingEnvironment = hostingEnvironment;
    }

    [HttpGet("initiate")]
    public IActionResult Initiate()
    {
        _streamingService.Connections.Add(Response.Body);
    }

    [HttpPost("broadcast")]
    public async Task<IActionResult> Broadcast()
    {
        // Retrieve data submitted from POSTMAN.
        var data = _streamingService.AnalyzeStream(Request.Body);

        foreach (var stream in _streamingService.Connections)
        {
            try
            {
                await stream.WriteAsync(data, 0, data.Length);
            }
            catch (Exception exception)
            {
                stream.Dispose();
                _streamingService.Connections.Remove(stream);
            }
        }
    }
}