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); }
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); } }
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); } }