using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using JT808.Gateway.Abstractions; using JT808.Gateway.Abstractions.Enums; using Microsoft.Extensions.Logging; namespace JT808.Gateway.Session { /// /// /// 不支持变态类型:既发TCP和UDP /// public class JT808SessionManager { private readonly ILogger logger; private readonly IJT808SessionProducer SessionProducer; /// /// socket连接会话 /// public ConcurrentDictionary Sessions { get; } /// /// socket绑定的终端SIM连接会话 /// public ConcurrentDictionary TerminalPhoneNoSessions { get; } /// /// /// /// /// public JT808SessionManager( IJT808SessionProducer jT808SessionProducer, ILoggerFactory loggerFactory ) { SessionProducer = jT808SessionProducer; Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); TerminalPhoneNoSessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); logger = loggerFactory.CreateLogger(); } /// /// /// /// public JT808SessionManager(ILoggerFactory loggerFactory) { Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); TerminalPhoneNoSessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); logger = loggerFactory.CreateLogger(); } /// /// 获取会话总数量 /// public int TotalSessionCount { get { return Sessions.Count; } } /// /// 获取tcp会话数量 /// public int TcpSessionCount { get { return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp).Count(); } } /// /// 获取udp会话数量 /// public int UdpSessionCount { get { return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp).Count(); } } /// /// /// /// /// internal void TryLink(string terminalPhoneNo, IJT808Session session) { session.TerminalPhoneNo = terminalPhoneNo; DateTime curretDatetime = DateTime.Now; if (TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo, out IJT808Session cacheSession)) { if (session.SessionID != cacheSession.SessionID) { //从转发到直连的数据需要更新缓存 session.ActiveTime = curretDatetime; TerminalPhoneNoSessions.TryUpdate(terminalPhoneNo, session, cacheSession); cacheSession.Close(); //会话通知 if (SessionProducer != null) { SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline, terminalPhoneNo); } } else { cacheSession.ActiveTime = curretDatetime; TerminalPhoneNoSessions.TryUpdate(terminalPhoneNo, cacheSession, cacheSession); } } else { if (TerminalPhoneNoSessions.TryAdd(terminalPhoneNo, session)) { //会话通知 if (SessionProducer != null) { SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline, terminalPhoneNo); } } } } /// /// /// /// /// /// /// public IJT808Session TryLink(string terminalPhoneNo, Socket socket, EndPoint remoteEndPoint) { if (TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo, out IJT808Session currentSession)) { currentSession.ActiveTime = DateTime.Now; currentSession.TerminalPhoneNo = terminalPhoneNo; currentSession.RemoteEndPoint = remoteEndPoint; TerminalPhoneNoSessions.TryUpdate(terminalPhoneNo, currentSession, currentSession); } else { JT808UdpSession session = new JT808UdpSession(socket, remoteEndPoint); session.TerminalPhoneNo = terminalPhoneNo; Sessions.TryAdd(session.SessionID, session); TerminalPhoneNoSessions.TryAdd(terminalPhoneNo, session); currentSession = session; } //会话通知 //使用场景: //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 //有设备关联上来可以进行通知 例如:使用Redis发布订阅 if (SessionProducer != null) { SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline, terminalPhoneNo); } return currentSession; } /// /// /// /// /// internal bool TryAdd(IJT808Session session) { return Sessions.TryAdd(session.SessionID, session); } public async ValueTask TrySendByTerminalPhoneNoAsync(string terminalPhoneNo, byte[] data) { if (TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo, out var session)) { if (session.TransportProtocolType == JT808TransportProtocolType.tcp) { await session.Client.SendAsync(data, SocketFlags.None); } else { await session.Client.SendToAsync(data, SocketFlags.None, session.RemoteEndPoint); } return true; } else { return false; } } public async ValueTask TrySendBySessionIdAsync(string sessionId, byte[] data) { if (Sessions.TryGetValue(sessionId, out var session)) { if (session.TransportProtocolType == JT808TransportProtocolType.tcp) { await session.Client.SendAsync(data, SocketFlags.None); } else { await session.Client.SendToAsync(data, SocketFlags.None, session.RemoteEndPoint); } return true; } else { return false; } } public void RemoveByTerminalPhoneNo(string terminalPhoneNo) { if (TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo, out var removeTerminalPhoneNoSessions)) { // 处理转发过来的是数据 这时候通道对设备是1对多关系,需要清理垃圾数据 //1.用当前会话的通道Id找出通过转发过来的其他设备的终端号 var terminalPhoneNos = TerminalPhoneNoSessions.Where(w => w.Value.SessionID == removeTerminalPhoneNoSessions.SessionID).Select(s => s.Key).ToList(); //2.存在则一个个移除 string tmpTerminalPhoneNo = terminalPhoneNo; if (terminalPhoneNos.Count > 0) { //3.移除包括当前的设备号 foreach (var item in terminalPhoneNos) { TerminalPhoneNoSessions.TryRemove(item, out _); } tmpTerminalPhoneNo = string.Join(",", terminalPhoneNos); } if (Sessions.TryRemove(removeTerminalPhoneNoSessions.SessionID, out var removeSession)) { removeSession.Close(); if (logger.IsEnabled(LogLevel.Information)) logger.LogInformation($"[Session Remove]:{terminalPhoneNo}-{tmpTerminalPhoneNo}"); if (SessionProducer != null) { SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, tmpTerminalPhoneNo); } } } } public void RemoveBySessionId(string sessionId) { if (Sessions.TryRemove(sessionId, out var removeSession)) { var terminalPhoneNos = TerminalPhoneNoSessions.Where(w => w.Value.SessionID == sessionId).Select(s => s.Key).ToList(); if (terminalPhoneNos.Count > 0) { foreach (var item in terminalPhoneNos) { TerminalPhoneNoSessions.TryRemove(item, out _); } var tmpTerminalPhoneNo = string.Join(",", terminalPhoneNos); if (SessionProducer != null) { SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, tmpTerminalPhoneNo); } if (logger.IsEnabled(LogLevel.Information)) logger.LogInformation($"[Session Remove]:{tmpTerminalPhoneNo}"); } removeSession.Close(); } } public List GetTcpAll(Func predicate = null) { var query = TerminalPhoneNoSessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp); if (predicate != null) { query = query.Where(s => predicate(s.Value)); } return query.Select(s => (JT808TcpSession)s.Value).ToList(); } public IEnumerable GetTcpByPage(Func predicate = null) { var query = TerminalPhoneNoSessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp); if (predicate != null) { query = query.Where(s => predicate(s.Value)); } return query.Select(s => (JT808TcpSession)s.Value); } public List GetUdpAll(Func predicate = null) { var query = TerminalPhoneNoSessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp); if (predicate != null) { query = query.Where(s => predicate(s.Value)); } return query.Select(s => (JT808UdpSession)s.Value).ToList(); } public IEnumerable GetUdpByPage(Func predicate = null) { var query = TerminalPhoneNoSessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp); if (predicate != null) { query = query.Where(s => predicate(s.Value)); } return query.Select(s => (JT808UdpSession)s.Value); } } }