using HslCommunication.Core.Net; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace HslCommunication.Enthernet.Redis { /// /// Redis协议的订阅操作,一个对象订阅一个或是多个频道的信息 /// public class RedisSubscribe : NetworkXBase { #region Constructor /// /// 实例化一个发布订阅类的客户端,需要指定ip地址,端口,及订阅关键字 /// /// 服务器的IP地址 /// 服务器的端口号 /// 订阅关键字 public RedisSubscribe( string ipAddress, int port, string[] keys ) { endPoint = new IPEndPoint( IPAddress.Parse( ipAddress ), port ); keyWords = keys; if (keys == null) { throw new Exception( StringResources.Language.KeyIsNotAllowedNull ); } } /// /// 实例化一个发布订阅类的客户端,需要指定ip地址,端口,及订阅关键字 /// /// 服务器的IP地址 /// 服务器的端口号 /// 订阅关键字 public RedisSubscribe( string ipAddress, int port, string key ) { endPoint = new IPEndPoint( IPAddress.Parse( ipAddress ), port ); keyWords = new string[] { key }; if (string.IsNullOrEmpty( key )) { throw new Exception( StringResources.Language.KeyIsNotAllowedNull ); } } #endregion #region Private Method private OperateResult CreatePush( ) { CoreSocket?.Close( ); OperateResult connect = CreateSocketAndConnect( endPoint, 5000 ); if (!connect.IsSuccess) return connect; // 密码的验证 if (!string.IsNullOrEmpty( this.Password )) { OperateResult check = Send( connect.Content, RedisHelper.PackStringCommand( new string[] { "AUTH", this.Password } ) ); if (!check.IsSuccess) return check; OperateResult checkResult = RedisHelper.ReceiveCommand( connect.Content ); if (!checkResult.IsSuccess) return checkResult; string msg = Encoding.UTF8.GetString( checkResult.Content ); if (!msg.StartsWith( "+OK" )) return new OperateResult( msg ); } List lists = new List( ); lists.Add( "SUBSCRIBE" ); lists.AddRange( keyWords ); OperateResult send = Send( connect.Content, RedisHelper.PackStringCommand( lists.ToArray( ) ) ); if (!send.IsSuccess) return send; CoreSocket = connect.Content; try { connect.Content.BeginReceive( new byte[0], 0, 0, SocketFlags.None, new AsyncCallback( ReceiveCallBack ), connect.Content ); } catch(Exception ex) { return new OperateResult( ex.Message ); } return OperateResult.CreateSuccessResult( ); } private void ReceiveCallBack( IAsyncResult ar ) { if(ar.AsyncState is Socket socket) { try { int receive = socket.EndReceive( ar ); OperateResult read = RedisHelper.ReceiveCommand( socket ); if (!read.IsSuccess) { SocketReceiveException( null ); return; } else { socket.BeginReceive( new byte[0], 0, 0, SocketFlags.None, new AsyncCallback( ReceiveCallBack ), socket ); } OperateResult data = RedisHelper.GetStringsFromCommandLine( read.Content ); if (!data.IsSuccess) { LogNet?.WriteWarn( data.Message ); return; } if(data.Content[0].ToUpper() == "SUBSCRIBE") { return; } else if(data.Content[0].ToUpper( ) == "MESSAGE") { action?.Invoke( data.Content[1], data.Content[2] ); } else { LogNet?.WriteWarn( data.Content[0] ); } } catch (ObjectDisposedException) { // 通常是主动退出 return; } catch(Exception ex) { SocketReceiveException( ex ); } } } private void SocketReceiveException( Exception ex ) { // 发生异常的时候需要进行重新连接 while (true) { if (ex != null) LogNet?.WriteException( "Offline", ex ); Console.WriteLine( StringResources.Language.ReConnectServerAfterTenSeconds ); System.Threading.Thread.Sleep( this.reconnectTime ); if (CreatePush( ).IsSuccess) { Console.WriteLine( StringResources.Language.ReConnectServerSuccess ); break; } } } #endregion #region Public Properties /// /// 如果Redis服务器设置了密码,此处就需要进行设置。必须在CreatePush方法调用前设置 /// public string Password { get; set; } #endregion #region Public Method /// /// 创建数据推送服务 /// /// 触发数据推送的委托 /// 是否创建成功 public OperateResult CreatePush( Action pushCallBack ) { action = pushCallBack; return CreatePush( ); } /// /// 关闭消息推送的界面 /// public void ClosePush( ) { action = null; CoreSocket?.Close( ); } #endregion #region Private Member private IPEndPoint endPoint; // 服务器的地址及端口信息 private string[] keyWords = null; // 缓存的订阅关键字 private Action action; // 服务器推送后的回调方法 private int reconnectTime = 10000; // 重连服务器的时间 #endregion #region Object Override /// /// 返回表示当前对象的字符串 /// /// 字符串信息 public override string ToString( ) { return $"RedisSubscribe[{endPoint}]"; } #endregion } }