protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Task.Run(() => {
                while (true)
                {
                    try
                    {
                        var hasSessions = HttpSessionManager.GetAll().Where(m => DateTime.Now.Subtract(m.StartTime).TotalSeconds > 60 && m.RTPVideoType == Metadata.RTPVideoType.Http_Hls).ToList();//所有http 的 hls短链接
                        foreach (var item in hasSessions)
                        {
                            var key = $"{item.Sim}_{item.ChannelNo}";
                            HttpSessionManager.TryRemove(item.SessionId);//超过120s未访问。
                            //清楚所有hls文件
                            string filepath = Path.Combine(Configuration.HlsRootDirectory, key);
                            if (Directory.Exists(filepath))
                            {
                                Directory.Delete(filepath, true);
                            }
                            hLSPathStorage.RemoveAllPath(key);//移除所有缓存

                            if (logger.IsEnabled(LogLevel.Debug))
                            {
                                logger.LogDebug($"{System.Text.Json.JsonSerializer.Serialize(item)},清楚session");
                            }
                            var hasTcpSession  = HttpSessionManager.GetAllBySimAndChannelNo(item.Sim.TrimStart('0'), item.ChannelNo).Any(m => m.IsWebSocket);                                    //是否存在tcp的 socket链接
                            var httpFlvSession = HttpSessionManager.GetAllBySimAndChannelNo(item.Sim.TrimStart('0'), item.ChannelNo).Any(m => m.RTPVideoType == Metadata.RTPVideoType.Http_Flv); //是否存在http的 flv长链接
                            if (!hasTcpSession && !httpFlvSession)
                            {
                                //不存在websocket链接和http-flv链接时,主动断开设备链接以节省流量
                                //移除tcpsession,断开设备链接
                                if (SessionManager != null)
                                {
                                    SessionManager.RemoveByTerminalPhoneNo(item.Sim.TrimStart('0'));
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogError(ex, ex.Message);
                    }
                    Thread.Sleep(TimeSpan.FromSeconds(30));//30s 执行一次
                }
            }, stoppingToken);
        }
Ejemplo n.º 2
0
        private async ValueTask ProcessRequestAsync(HttpListenerContext context, IPrincipal principal)
        {
            if (context.Request.RawUrl.StartsWith("/favicon.ico"))
            {
                context.Http404();
                return;
            }
            if (context.Request.RawUrl.Contains(".m3u8") || context.Request.RawUrl.Contains(".ts"))
            {
                hLSRequestManager.HandleHlsRequest(context, principal);
                return;
            }
            if (Logger.IsEnabled(LogLevel.Trace))
            {
                Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}");
            }
            if (Logger.IsEnabled(LogLevel.Trace))
            {
                Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}");
            }
            string sim     = context.Request.QueryString.Get("sim");
            string channel = context.Request.QueryString.Get("channel");

            if (string.IsNullOrEmpty(sim) || string.IsNullOrEmpty(channel))
            {
                await context.Http400();

                return;
            }
            int.TryParse(channel, out int channelNo);
            if (context.Request.IsWebSocketRequest)
            {
                HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null, keepAliveInterval : TimeSpan.FromSeconds(5));

                var jT1078HttpContext = new JT1078HttpContext(context, wsContext, principal);
                jT1078HttpContext.Sim          = sim;
                jT1078HttpContext.ChannelNo    = channelNo;
                jT1078HttpContext.RTPVideoType = RTPVideoType.Ws_Flv;
                SessionManager.TryAdd(jT1078HttpContext);
                //这个发送出去,flv.js就报错了
                //await jT1078HttpContext.WebSocketSendHelloAsync();
                await Task.Factory.StartNew(async(state) =>
                {
                    //https://www.bejson.com/httputil/websocket/
                    //ws://localhost:15555?token=22&sim=1221&channel=1
                    var websocketContext = state as JT1078HttpContext;
                    while (websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Open ||
                           websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Connecting)
                    {
                        var buffer = ArrayPool <byte> .Shared.Rent(256);
                        try
                        {
                            //客户端主动断开需要有个线程去接收通知,不然会客户端会卡死直到超时
                            WebSocketReceiveResult receiveResult = await websocketContext.WebSocketContext.WebSocket.ReceiveAsync(buffer, CancellationToken.None);
                            if (receiveResult.EndOfMessage)
                            {
                                if (receiveResult.Count > 0)
                                {
                                    var data = buffer.AsSpan().Slice(0, receiveResult.Count).ToArray();
                                    if (Logger.IsEnabled(LogLevel.Trace))
                                    {
                                        Logger.LogTrace($"[ws receive]:{Encoding.UTF8.GetString(data)}");
                                    }
                                    await websocketContext.WebSocketSendTextAsync(data);
                                }
                            }
                        }
                        finally
                        {
                            ArrayPool <byte> .Shared.Return(buffer);
                        }
                    }
                    if (Logger.IsEnabled(LogLevel.Information))
                    {
                        Logger.LogInformation($"[ws close]:{websocketContext.SessionId}-{websocketContext.Sim}-{websocketContext.ChannelNo}-{websocketContext.StartTime:yyyyMMddhhmmss}");
                    }
                    SessionManager.TryRemove(websocketContext.SessionId);
                }, jT1078HttpContext);
            }
            else
            {
                var jT1078HttpContext = new JT1078HttpContext(context, principal);
                jT1078HttpContext.Sim          = sim;
                jT1078HttpContext.RTPVideoType = RTPVideoType.Http_Flv;
                jT1078HttpContext.ChannelNo    = channelNo;
                SessionManager.TryAdd(jT1078HttpContext);
            }
        }
Ejemplo n.º 3
0
        private async ValueTask ProcessRequestAsync(HttpListenerContext context, IPrincipal principal)
        {
            if (context.Request.RawUrl.StartsWith("/favicon.ico"))
            {
                context.Http404();
                return;
            }
            var    uri         = new Uri(context.Request.RawUrl);
            string url         = uri.AbsolutePath;
            var    queryParams = uri.Query.Substring(1, uri.Query.Length - 1).Split('&');

            if (queryParams.Length < 2)
            {
                context.Http404();
                return;
            }
            if (url.EndsWith(".m3u8") || url.EndsWith(".ts"))
            {
                string key = $"{queryParams[0].Split('=')[1]}_{queryParams[1].Split('=')[1]}";//默认queryParams第一个参数是终端号,第二个参数是通道号
                memoryCache.GetOrCreate(key, (cacheEntry) => {
                    cacheEntry.SetSlidingExpiration(TimeSpan.FromSeconds(20));
                    cacheEntry.RegisterPostEvictionCallback((key, value, reason, state) => {
                        //当清空httpssion时,同时清除tcpsseion
                    });
                    return(DateTime.Now);
                });
                string filename = Path.GetFileName(url);
                string filepath = Path.Combine(Configuration.HlsRootDirectory, key, filename);
                if (!File.Exists(filepath))
                {
                    context.Http404();
                    return;
                }
                try
                {
                    using (FileStream sr = new FileStream(filepath, FileMode.Open))
                    {
                        context.Response.ContentLength64 = sr.Length;
                        await sr.CopyToAsync(context.Response.OutputStream);
                    }
                    string ext = Path.GetExtension(filename);
                    if (ext == ".m3u8")
                    {
                        context.Response.ContentType = m3u8Mime;
                    }
                    else if (ext == ".ts")
                    {
                        context.Response.ContentType = tsMime;
                    }
                    context.Response.StatusCode = (int)HttpStatusCode.OK;
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, $"{context.Request.RawUrl}");
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                }
                finally
                {
                    context.Response.OutputStream.Close();
                    context.Response.Close();
                }
                return;
            }
            if (Logger.IsEnabled(LogLevel.Trace))
            {
                Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}");
            }
            string sim     = context.Request.QueryString.Get("sim");
            string channel = context.Request.QueryString.Get("channel");

            if (string.IsNullOrEmpty(sim) || string.IsNullOrEmpty(channel))
            {
                await context.Http400();

                return;
            }
            int.TryParse(channel, out int channelNo);
            if (context.Request.IsWebSocketRequest)
            {
                HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null, keepAliveInterval : TimeSpan.FromSeconds(5));

                var jT1078HttpContext = new JT1078HttpContext(context, wsContext, principal);
                jT1078HttpContext.Sim       = sim;
                jT1078HttpContext.ChannelNo = channelNo;
                SessionManager.TryAdd(jT1078HttpContext);
                await jT1078HttpContext.WebSocketSendHelloAsync();

                await Task.Factory.StartNew(async(state) =>
                {
                    //https://www.bejson.com/httputil/websocket/
                    //ws://localhost:15555?token=22&sim=1221&channel=1
                    var websocketContext = state as JT1078HttpContext;
                    while (websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Open ||
                           websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Connecting)
                    {
                        var buffer = ArrayPool <byte> .Shared.Rent(256);
                        try
                        {
                            //客户端主动断开需要有个线程去接收通知,不然会客户端会卡死直到超时
                            WebSocketReceiveResult receiveResult = await websocketContext.WebSocketContext.WebSocket.ReceiveAsync(buffer, CancellationToken.None);
                            if (receiveResult.EndOfMessage)
                            {
                                if (receiveResult.Count > 0)
                                {
                                    var data = buffer.AsSpan().Slice(0, receiveResult.Count).ToArray();
                                    if (Logger.IsEnabled(LogLevel.Trace))
                                    {
                                        Logger.LogTrace($"[ws receive]:{Encoding.UTF8.GetString(data)}");
                                    }
                                    await websocketContext.WebSocketSendTextAsync(data);
                                }
                            }
                        }
                        finally
                        {
                            ArrayPool <byte> .Shared.Return(buffer);
                        }
                    }
                    if (Logger.IsEnabled(LogLevel.Information))
                    {
                        Logger.LogInformation($"[ws close]:{websocketContext.SessionId}-{websocketContext.Sim}-{websocketContext.ChannelNo}-{websocketContext.StartTime:yyyyMMddhhmmss}");
                    }
                    SessionManager.TryRemove(websocketContext.SessionId);
                }, jT1078HttpContext);
            }
            else
            {
                var jT1078HttpContext = new JT1078HttpContext(context, principal);
                jT1078HttpContext.Sim       = sim;
                jT1078HttpContext.ChannelNo = channelNo;
                SessionManager.TryAdd(jT1078HttpContext);
            }
        }