using HslCommunication.Core; using HslCommunication.Core.IMessage; using HslCommunication.Core.Net; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.IO; namespace HslCommunication.Enthernet.Redis { /// /// 这是一个redis的客户端类,支持读取,写入,发布订阅,但是不支持订阅,如果需要订阅,请使用另一个类 /// public class RedisClient : NetworkDoubleBase { #region Constructor /// /// 实例化一个客户端的对象,用于和服务器通信 /// /// 服务器的ip地址 /// 服务器的端口号 /// 密码,如果服务器没有设置,密码设置为null public RedisClient( string ipAddress, int port, string password ) { IpAddress = ipAddress; Port = port; ReceiveTimeOut = 30000; this.password = password; } /// /// 实例化一个客户端对象,需要手动指定Ip地址和端口 /// /// 密码,如果服务器没有设置,密码设置为null public RedisClient( string password ) { ReceiveTimeOut = 30000; this.password = password; } #endregion #region Override /// /// 如果设置了密码,对密码进行验证 /// /// 网络的套接字服务 /// 是否成功的对象 protected override OperateResult InitializationOnConnect( Socket socket ) { if (!string.IsNullOrEmpty( this.password )) { byte[] command = RedisHelper.PackStringCommand( new string[] { "AUTH", this.password } ); OperateResult read = ReadFromCoreServer(socket, command ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); string msg = Encoding.UTF8.GetString( read.Content ); if (!msg.StartsWith( "+" )) return new OperateResult( msg ); return OperateResult.CreateSuccessResult( msg.Substring( 1 ).TrimEnd( '\r', '\n' ) ); } return base.InitializationOnConnect( socket ); } /// /// 在其他指定的套接字上,使用报文来通讯,传入需要发送的消息,返回一条完整的数据指令 /// /// 指定的套接字 /// 发送的完整的报文信息 /// /// 无锁的基于套接字直接进行叠加协议的操作。 /// /// /// 假设你有一个自己的socket连接了设备,本组件可以直接基于该socket实现modbus读取,三菱读取,西门子读取等等操作,前提是该服务器支持多协议,虽然这个需求听上去比较变态,但本组件支持这样的操作。 /// /// /// 接收的完整的报文信息 public override OperateResult ReadFromCoreServer( Socket socket, byte[] send ) { OperateResult sendResult = Send( socket, send ); if (!sendResult.IsSuccess) return OperateResult.CreateFailedResult( sendResult ); string tmp = BasicFramework.SoftBasic.ByteToHexString( send, ' ' ); // 接收超时时间大于0时才允许接收远程的数据 if (ReceiveTimeOut < 0) return OperateResult.CreateSuccessResult( new byte[0] ); // 接收数据信息 return RedisHelper.ReceiveCommand( socket ); } #endregion #region Customer /// /// 自定义的指令交互方法,该指令用空格分割,举例:LTRIM AAAAA 0 999 就是收缩列表,GET AAA 就是获取键值,需要对返回的数据进行二次分析 /// /// 举例:LTRIM AAAAA 0 999 就是收缩列表,GET AAA 就是获取键值 /// 从服务器返回的结果数据对象 public OperateResult ReadCustomer( string command ) { byte[] byteCommand = RedisHelper.PackStringCommand( command.Split( ' ' ) ); OperateResult read = ReadFromCoreServer( byteCommand ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); return OperateResult.CreateSuccessResult( Encoding.UTF8.GetString( read.Content ) ); } #endregion #region Base Operate /// /// 向服务器请求指定,并返回数字的结果对象 /// /// 命令数组 /// 数字的结果对象 public OperateResult OperateNumberFromServer(string[] commands) { byte[] command = RedisHelper.PackStringCommand( commands ); OperateResult read = ReadFromCoreServer( command ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); string msg = Encoding.UTF8.GetString( read.Content ); if (!msg.StartsWith( ":" )) return new OperateResult( msg ); return RedisHelper.GetNumberFromCommandLine( read.Content ); } /// /// 向服务器请求指令,并返回long数字的结果对象 /// /// 命令数组 /// long数字的结果对象 public OperateResult OperateLongNumberFromServer(string[] commands) { byte[] command = RedisHelper.PackStringCommand( commands ); OperateResult read = ReadFromCoreServer( command ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); string msg = Encoding.UTF8.GetString( read.Content ); if (!msg.StartsWith( ":" )) return new OperateResult( msg ); return RedisHelper.GetLongNumberFromCommandLine( read.Content ); } /// /// 向服务器请求指令,并返回字符串的结果对象 /// /// 命令数组 /// 字符串的结果对象 public OperateResult OperateStringFromServer(string[] commands) { byte[] command = RedisHelper.PackStringCommand( commands ); OperateResult read = ReadFromCoreServer( command ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); return RedisHelper.GetStringFromCommandLine( read.Content ); } /// /// 向服务器请求指令,并返回字符串数组的结果对象 /// /// 命令数组 /// 字符串数组的结果对象 public OperateResult OperateStringsFromServer(string[] commands) { byte[] command = RedisHelper.PackStringCommand( commands ); OperateResult read = ReadFromCoreServer( command ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); return RedisHelper.GetStringsFromCommandLine( read.Content ); } /// /// 向服务器请求指令,并返回状态的结果对象,通常用于写入的判断,或是请求类型的判断 /// /// 命令数组 /// 是否成功的结果对象 public OperateResult OperateStatusFromServer(string[] commands) { byte[] command = RedisHelper.PackStringCommand( commands ); OperateResult read = ReadFromCoreServer( command ); if (!read.IsSuccess) return OperateResult.CreateFailedResult( read ); string msg = Encoding.UTF8.GetString( read.Content ); if (!msg.StartsWith( "+" )) return new OperateResult( msg ); return OperateResult.CreateSuccessResult( msg.Substring( 1 ).TrimEnd( '\r', '\n' ) ); } #endregion #region Key Operate /// /// 删除给定的一个或多个 key 。不存在的 key 会被忽略。 /// /// 关键字 /// 被删除 key 的数量。 public OperateResult DeleteKey( string[] keys ) { List list = new List( ); list.Add( "DEL" ); list.AddRange( keys ); return OperateNumberFromServer( list.ToArray( ) ); } /// /// 删除给定的一个或多个 key 。不存在的 key 会被忽略。 /// /// 关键字 /// 被删除 key 的数量。 public OperateResult DeleteKey( string key ) { return DeleteKey( new string[] { key } ); } /// /// 检查给定 key 是否存在。若 key 存在,返回 1 ,否则返回 0 。 /// /// 关键字 /// 若 key 存在,返回 1 ,否则返回 0 。 public OperateResult ExistsKey( string key ) { return OperateNumberFromServer( new string[] { "EXISTS", key } ); } /// /// 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。设置成功返回 1 。当 key 不存在或者不能为 key 设置生存时间时,返回 0 。 /// /// 关键字 /// /// 设置成功返回 1 。当 key 不存在或者不能为 key 设置生存时间时,返回 0 。 /// public OperateResult ExpireKey( string key ) { return OperateNumberFromServer( new string[] { "EXPIRE", key } ); } /// /// 查找所有符合给定模式 pattern 的 key 。 /// * 匹配数据库中所有 key。 /// h?llo 匹配 hello , hallo 和 hxllo 等。 /// h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。 /// /// 给定模式 /// 符合给定模式的 key 列表。 public OperateResult ReadAllKeys( string pattern ) { return OperateStringsFromServer( new string[] { "KEYS", pattern } ); } /// /// 将当前数据库的 key 移动到给定的数据库 db 当中。 /// 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ,或者 key 不存在于当前数据库,那么 MOVE 没有任何效果。 /// 因此,也可以利用这一特性,将 MOVE 当作锁(locking)原语(primitive)。 /// /// 关键字 /// 数据块 /// 是否移动成功 public OperateResult MoveKey( string key, int db ) { return OperateStatusFromServer( new string[] { "MOVE", key, db.ToString( ) } ); } /// /// 移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。 /// 当生存时间移除成功时,返回 1 . /// 如果 key 不存在或 key 没有设置生存时间,返回 0 。 /// /// 关键字 /// /// 当生存时间移除成功时,返回 1 . /// 如果 key 不存在或 key 没有设置生存时间,返回 0 。 /// public OperateResult PersistKey( string key ) { return OperateNumberFromServer( new string[] { "PERSIST", key } ); } /// /// 从当前数据库中随机返回(不删除)一个 key 。 /// 当数据库不为空时,返回一个 key 。 /// 当数据库为空时,返回 nil 。 /// /// /// 当数据库不为空时,返回一个 key 。 /// 当数据库为空时,返回 nil 。 /// public OperateResult ReadRandomKey( ) { return OperateStringFromServer( new string[] { "RANDOMKEY" } ); } /// /// 将 key 改名为 newkey 。 /// 当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。 /// 当 newkey 已经存在时, RENAME 命令将覆盖旧值。 /// /// 旧的key /// 新的key /// /// 改名成功时提示 OK ,失败时候返回一个错误。 /// public OperateResult RenameKey( string key1, string key2 ) { return OperateStatusFromServer( new string[] { "RENAME", key1, key2 } ); } /// /// 返回 key 所储存的值的类型。none (key不存在),string (字符串),list (列表),set (集合),zset (有序集),hash (哈希表) /// /// 关键字 /// 类型 public OperateResult ReadKeyType( string key ) { return OperateStatusFromServer( new string[] { "TYPE", key } ); } #endregion #region String Operate /// /// 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。 /// 如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。 /// 返回追加 value 之后, key 中字符串的长度。 /// /// 关键字 /// 数值 /// /// 追加 value 之后, key 中字符串的长度。 /// public OperateResult AppendKey( string key, string value ) { return OperateNumberFromServer( new string[] { "APPEND", key, value } ); } /// /// 将 key 中储存的数字值减一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。 /// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 /// 本操作的值限制在 64 位(bit)有符号数字表示之内。 /// 返回执行 DECR 命令之后 key 的值。 /// /// 关键字 /// 执行 DECR 命令之后 key 的值。 public OperateResult DecrementKey( string key ) { return OperateLongNumberFromServer( new string[] { "DECR", key } ); } /// /// 将 key 所储存的值减去减量 decrement 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。 /// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 /// 本操作的值限制在 64 位(bit)有符号数字表示之内。 /// 返回减去 decrement 之后, key 的值。 /// /// 关键字 /// 操作的值 /// 返回减去 decrement 之后, key 的值。 public OperateResult DecrementKey( string key, long value ) { return OperateLongNumberFromServer( new string[] { "DECRBY", key, value.ToString( ) } ); } /// /// 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。 /// 假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。 /// /// 关键字 /// 当 key 不存在时,返回 nil ,否则,返回 key 的值。 public OperateResult ReadKey( string key ) { return OperateStringFromServer( new string[] { "GET", key } ); } /// /// 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。 /// 负数偏移量表示从字符串最后开始计数, -1 表示最后一个字符, -2 表示倒数第二个,以此类推。 /// 返回截取得出的子字符串。 /// /// 关键字 /// 截取开始的位置 /// 截取结束的位置 /// 返回截取得出的子字符串。 public OperateResult ReadKeyRange( string key, int start, int end ) { return OperateStringFromServer( new string[] { "GETRANGE", key, start.ToString( ), end.ToString( ) } ); } /// /// 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。 /// /// 关键字 /// 新的值 /// 返回给定 key 的旧值。当 key 没有旧值时,也即是, key 不存在时,返回 nil 。 public OperateResult ReadAndWriteKey( string key, string value ) { return OperateStringFromServer( new string[] { "GETSET", key, value } ); } /// /// 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。 /// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 /// 返回执行 INCR 命令之后 key 的值。 /// /// 关键字 /// 返回执行 INCR 命令之后 key 的值。 public OperateResult IncrementKey( string key ) { return OperateLongNumberFromServer( new string[] { "INCR", key } ); } /// /// 将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。 /// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 /// /// 关键字 /// 增量数据 /// 加上 increment 之后, key 的值。 public OperateResult IncrementKey( string key, long value ) { return OperateLongNumberFromServer( new string[] { "INCRBY", key, value.ToString( ) } ); } /// /// 将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBYFLOAT 操作。 /// 如果命令执行成功,那么 key 的值会被更新为(执行加法之后的)新值,并且新值会以字符串的形式返回给调用者 /// /// 关键字 /// 增量数据 /// 执行命令之后 key 的值。 public OperateResult IncrementKey( string key, float value ) { return OperateStringFromServer( new string[] { "INCRBYFLOAT", key, value.ToString( ) } ); } /// /// 返回所有(一个或多个)给定 key 的值。 /// 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 null 。因此,该命令永不失败。 /// /// 关键字数组 /// 一个包含所有给定 key 的值的列表。 public OperateResult ReadKey( string[] keys ) { List list = new List( ); list.Add( "MGET" ); list.AddRange( keys ); return OperateStringsFromServer( list.ToArray( ) ); } /// /// 同时设置一个或多个 key-value 对。 /// 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。 /// /// 关键字数组 /// 值数组 /// 总是返回 OK (因为 MSET 不可能失败) public OperateResult WriteKey( string[] keys, string[] values ) { if (keys == null) throw new ArgumentNullException( "keys" ); if (values == null) throw new ArgumentNullException( "values" ); if (keys.Length != values.Length) throw new ArgumentException( "Two arguement not same length" ); List list = new List( ); list.Add( "MSET" ); for (int i = 0; i < keys.Length; i++) { list.Add( keys[i] ); list.Add( values[i] ); } return OperateStatusFromServer( list.ToArray( ) ); } /// /// 将字符串值 value 关联到 key 。 /// 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。 /// 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。 /// /// 关键字 /// 数据值 /// SET 在设置操作成功完成时,才返回 OK 。 public OperateResult WriteKey( string key, string value ) { return OperateStatusFromServer( new string[] { "SET", key, value } ); } /// /// 将字符串值 value 关联到 key 。并发布一个订阅的频道数据,都成功时,才返回成功 /// /// 关键字 /// 数据值 /// 是否成功的结果对象 public OperateResult WriteAndPublishKey(string key, string value ) { OperateResult write = WriteKey( key, value ); if (!write.IsSuccess) return write; return Publish( key, value ); } /// /// 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, SETEX 命令将覆写旧值。 /// /// 关键字 /// 数值 /// 生存时间,单位秒 /// 设置成功时返回 OK 。当 seconds 参数不合法时,返回一个错误。 public OperateResult WriteExpireKey( string key, string value, long seconds ) { return OperateStatusFromServer( new string[] { "SETEX", key, seconds.ToString( ), value } ); } /// /// 将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。设置成功,返回 1 。设置失败,返回 0 。 /// /// 关键字 /// 数据值 /// 设置成功,返回 1 。设置失败,返回 0 。 public OperateResult WriteKeyIfNotExists( string key, string value ) { return OperateNumberFromServer( new string[] { "SETNX", key, value } ); } /// /// 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。不存在的 key 当作空白字符串处理。返回被 SETRANGE 修改之后,字符串的长度。 /// /// 关键字 /// 数值 /// 起始的偏移量 /// 被 SETRANGE 修改之后,字符串的长度。 public OperateResult WriteKeyRange( string key, string value, int offset ) { return OperateNumberFromServer( new string[] { "SETRANGE", key, offset.ToString( ), value } ); } /// /// 返回 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。返回符串值的长度。当 key 不存在时,返回 0 。 /// /// 关键字 /// 字符串值的长度。当 key 不存在时,返回 0 。 public OperateResult ReadKeyLength( string key ) { return OperateNumberFromServer( new string[] { "STRLEN", key } ); } #endregion #region List Operate /// /// 将值 value 插入到列表 key 当中,位于值 pivot 之前。 /// 当 pivot 不存在于列表 key 时,不执行任何操作。 /// 当 key 不存在时, key 被视为空列表,不执行任何操作。 /// 如果 key 不是列表类型,返回一个错误。 /// /// 关键字 /// 数值 /// 原先的值 /// /// 如果命令执行成功,返回插入操作完成之后,列表的长度。 /// 如果没有找到 pivot ,返回 -1 。 /// 如果 key 不存在或为空列表,返回 0 。 /// public OperateResult ListInsertBefore( string key, string value, string pivot ) { return OperateNumberFromServer( new string[] { "LINSERT", key, "BEFORE", pivot, value } ); } /// /// 将值 value 插入到列表 key 当中,位于值 pivot 之后。 /// 当 pivot 不存在于列表 key 时,不执行任何操作。 /// 当 key 不存在时, key 被视为空列表,不执行任何操作。 /// 如果 key 不是列表类型,返回一个错误。 /// /// 关键字 /// 数值 /// 原先的值 /// /// 如果命令执行成功,返回插入操作完成之后,列表的长度。 /// 如果没有找到 pivot ,返回 -1 。 /// 如果 key 不存在或为空列表,返回 0 。 /// public OperateResult ListInsertAfter( string key, string value, string pivot ) { return OperateNumberFromServer( new string[] { "LINSERT", key, "AFTER", pivot, value } ); } /// /// 返回列表 key 的长度。如果 key 不存在,则 key 被解释为一个空列表,返回 0 .如果 key 不是列表类型,返回一个错误。 /// /// 关键字 /// 列表 key 的长度。 public OperateResult GetListLength( string key ) { return OperateNumberFromServer( new string[] { "LLEN", key } ); } /// /// 返回列表 key 中,下标为 index 的元素。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 /// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。如果 key 不是列表类型,返回一个错误。 /// /// 关键字 /// 索引位置 /// 列表中下标为 index 的元素。如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。 public OperateResult ReadListByIndex( string key, long index ) { return OperateStringFromServer( new string[] { "LINDEX", key, index.ToString( ) } ); } /// /// 移除并返回列表 key 的头元素。列表的头元素。当 key 不存在时,返回 nil 。 /// /// 关键字信息 /// 列表的头元素。 public OperateResult ListLeftPop( string key ) { return OperateStringFromServer( new string[] { "LPOP", key } ); } /// /// 将一个或多个值 value 插入到列表 key 的表头,如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。返回执行 LPUSH 命令后,列表的长度。 /// /// 关键字 /// 值 /// 执行 LPUSH 命令后,列表的长度。 public OperateResult ListLeftPush( string key, string value ) { return ListLeftPush( key, new string[] { value } ); } /// /// 将一个或多个值 value 插入到列表 key 的表头,如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。返回执行 LPUSH 命令后,列表的长度。 /// /// 关键字 /// 值 /// 执行 LPUSH 命令后,列表的长度。 public OperateResult ListLeftPush( string key, string[] values ) { List list = new List( ); list.Add( "LPUSH" ); list.Add( key ); list.AddRange( values ); return OperateNumberFromServer( list.ToArray( ) ); } /// /// 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不做。 /// 返回LPUSHX 命令执行之后,表的长度。 /// /// 关键字 /// 值 /// 是否插入数据成功 public OperateResult ListLeftPushX( string key, string value ) { return OperateNumberFromServer( new string[] { "LPUSHX", key, value } ); } /// /// 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。 /// 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 /// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 /// 返回一个列表,包含指定区间内的元素。 /// /// 关键字 /// 开始的索引 /// 结束的索引 /// 返回一个列表,包含指定区间内的元素。 public OperateResult ListRange( string key, long start, long stop ) { return OperateStringsFromServer( new string[] { "LRANGE", key, start.ToString( ), stop.ToString( ) } ); } /// /// 根据参数 count 的值,移除列表中与参数 value 相等的元素。count 的值可以是以下几种: /// count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。 /// count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。 /// count = 0 : 移除表中所有与 value 相等的值。 /// 返回被移除的数量。 /// /// 关键字 /// 移除参数 /// 匹配的值 /// 被移除元素的数量。因为不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM 命令总是返回 0 。 public OperateResult ListRemoveElementMatch( string key, long count, string value ) { return OperateNumberFromServer( new string[] { "LREM", key, count.ToString( ), value } ); } /// /// 设置数组的某一个索引的数据信息,当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。 /// /// 关键字 /// 索引位置 /// 值 /// 操作成功返回 ok ,否则返回错误信息。 public OperateResult ListSet( string key, long index, string value ) { return OperateStatusFromServer( new string[] { "LSET", key.ToString( ), index.ToString( ), value } ); } /// /// 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 /// 举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。 /// 下标( index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 /// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 /// 当 key 不是列表类型时,返回一个错误。 /// /// 关键字信息 /// 起始的索引信息 /// 结束的索引信息 /// 操作成功返回 ok ,否则返回错误信息。 public OperateResult ListTrim( string key, long start, long end ) { return OperateStatusFromServer( new string[] { "LTRIM", key, start.ToString( ), end.ToString( ) } ); } /// /// 移除并返回列表 key 的尾元素。当 key 不存在时,返回 nil 。 /// /// 关键字信息 /// 列表的尾元素。 public OperateResult ListRightPop( string key ) { return OperateStringFromServer( new string[] { "RPOP", key } ); } /// /// 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作: /// 1. 将列表 source 中的最后一个元素( 尾元素)弹出,并返回给客户端。 /// 2. 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。 /// 举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c , destination 列表有元素 x, y, z ,执行 RPOPLPUSH source destination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。 /// 如果 source 不存在,值 nil 被返回,并且不执行其他动作。 /// 如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转( rotation)操作。 /// /// 第一个关键字 /// 第二个关键字 /// 返回的移除的对象 public OperateResult ListRightPopLeftPush( string key1, string key2 ) { return OperateStringFromServer( new string[] { "RPOPLPUSH", key1, key2 } ); } /// /// 将一个或多个值 value 插入到列表 key 的表尾(最右边)。 /// 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。 /// /// 关键字 /// 值 /// 返回执行 RPUSH 操作后,表的长度。 public OperateResult ListRightPush( string key, string value ) { return ListRightPush( key, new string[] { value } ); } /// /// 将一个或多个值 value 插入到列表 key 的表尾(最右边)。 /// 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c , /// 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。 /// 返回执行 RPUSH 操作后,表的长度。 /// /// 关键字 /// 值 /// 返回执行 RPUSH 操作后,表的长度。 public OperateResult ListRightPush( string key, string[] values ) { List list = new List( ); list.Add( "RPUSH" ); list.Add( key ); list.AddRange( values ); return OperateNumberFromServer( list.ToArray( ) ); } /// /// 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。 /// 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。 /// /// 关键字 /// 值 /// RPUSHX 命令执行之后,表的长度。 public OperateResult ListRightPushX( string key, string value ) { return OperateNumberFromServer( new string[] { "RPUSHX", key, value } ); } #endregion #region Hash Operate /// /// 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。 /// /// 关键字 /// 域 /// 被成功移除的域的数量,不包括被忽略的域。 public OperateResult DeleteHashKey( string key, string field ) { return DeleteHashKey( key, new string[] { field } ); } /// /// 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。返回被成功移除的域的数量,不包括被忽略的域。 /// /// 关键字 /// 所有的域 /// 返回被成功移除的域的数量,不包括被忽略的域。 public OperateResult DeleteHashKey( string key, string[] fields ) { List list = new List( ); list.Add( "HDEL" ); list.Add( key ); list.AddRange( fields ); return OperateNumberFromServer( list.ToArray( ) ); } /// /// 查看哈希表 key 中,给定域 field 是否存在。如果哈希表含有给定域,返回 1 。 /// 如果哈希表不含有给定域,或 key 不存在,返回 0 。 /// /// 关键字 /// 域 /// 如果哈希表含有给定域,返回 1 。如果哈希表不含有给定域,或 key 不存在,返回 0 。 public OperateResult ExistsHashKey( string key, string field ) { return OperateNumberFromServer( new string[] { "HEXISTS", key, field } ); } /// /// 返回哈希表 key 中给定域 field 的值。当给定域不存在或是给定 key 不存在时,返回 nil /// /// 关键值 /// 域 /// /// 给定域的值。 /// 当给定域不存在或是给定 key 不存在时,返回 nil 。 /// public OperateResult ReadHashKey( string key, string field ) { return OperateStringFromServer( new string[] { "HGET", key, field } ); } /// /// 返回哈希表 key 中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。 /// /// 关键值 /// /// 以列表形式返回哈希表的域和域的值。 /// 若 key 不存在,返回空列表。 /// public OperateResult ReadHashKeyAll( string key ) { return OperateStringsFromServer( new string[] { "HGETALL", key } ); } /// /// 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。 /// 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。 /// /// 关键字 /// 域 /// 增量值 /// 返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。 public OperateResult IncrementHashKey( string key, string field, long value ) { return OperateLongNumberFromServer( new string[] { "HINCRBY", key, field, value.ToString( ) } ); } /// /// 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。 /// 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。 /// /// 关键字 /// 域 /// 增量值 /// 返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。 public OperateResult IncrementHashKey( string key, string field, float value ) { return OperateStringFromServer( new string[] { "HINCRBYFLOAT", key, field, value.ToString( ) } ); } /// /// 返回哈希表 key 中的所有域。当 key 不存在时,返回一个空表。 /// /// 关键值 /// /// 一个包含哈希表中所有域的表。 /// 当 key 不存在时,返回一个空表。 /// public OperateResult ReadHashKeys( string key ) { return OperateStringsFromServer( new string[] { "HKEYS", key } ); } /// /// 返回哈希表 key 中域的数量。 /// /// 关键字 /// 哈希表中域的数量。当 key 不存在时,返回 0 。 public OperateResult ReadHashKeyLength( string key ) { return OperateNumberFromServer( new string[] { "HLEN", key } ); } /// /// 返回哈希表 key 中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个 nil 值。 /// 因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。 /// /// 关键值 /// 指定的域 /// /// 一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。 /// public OperateResult ReadHashKey( string key, string[] fields ) { List list = new List( ); list.Add( "HMGET" ); list.Add( key ); list.AddRange( fields ); return OperateStringsFromServer( list.ToArray( ) ); } /// /// 将哈希表 key 中的域 field 的值设为 value 。 /// 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。 /// 如果域 field 已经存在于哈希表中,旧值将被覆盖。 /// 如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。 /// 如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。 /// /// 关键字 /// 域 /// 数据值 /// /// 如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。 /// 如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。 /// public OperateResult WriteHashKey( string key, string field, string value ) { return OperateNumberFromServer( new string[] { "HSET", key, field, value } ); } /// /// 同时将多个 field-value (域-值)对设置到哈希表 key 中。 /// 此命令会覆盖哈希表中已存在的域。 /// 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。 /// /// 关键字 /// 域 /// 数据值 /// /// 如果命令执行成功,返回 OK 。 /// 当 key 不是哈希表(hash)类型时,返回一个错误 /// public OperateResult WriteHashKey( string key, string[] fields, string[] values ) { if (fields == null) throw new ArgumentNullException( "fields" ); if (values == null) throw new ArgumentNullException( "values" ); if (fields.Length != values.Length) throw new ArgumentException( "Two arguement not same length" ); List list = new List( ); list.Add( "HMSET" ); list.Add( key ); for (int i = 0; i < fields.Length; i++) { list.Add( fields[i] ); list.Add( values[i] ); } return OperateStatusFromServer( list.ToArray( ) ); } /// /// 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。若域 field 已经存在,该操作无效。 /// 设置成功,返回 1 。如果给定域已经存在且没有操作被执行,返回 0 。 /// /// 关键字 /// 域 /// 数据值 /// 设置成功,返回 1 。如果给定域已经存在且没有操作被执行,返回 0 。 public OperateResult WriteHashKeyNx( string key, string field, string value ) { return OperateNumberFromServer( new string[] { "HSETNX", key, field, value } ); } /// /// 返回哈希表 key 中所有域的值。当 key 不存在时,返回一个空表。 /// /// 关键值 /// /// 返回哈希表 key 中所有域的值。 /// 当 key 不存在时,返回一个空表。 /// public OperateResult ReadHashValues( string key ) { return OperateStringsFromServer( new string[] { "HVALS", key } ); } #endregion #region Server Operate /// /// SAVE 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。 /// /// 保存成功时返回 OK 。 public OperateResult Save( ) { return OperateStatusFromServer( new string[] { "SAVE" } ); } /// /// 在后台异步(Asynchronously)保存当前数据库的数据到磁盘。 /// BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。 /// /// 反馈信息。 public OperateResult SaveAsync( ) { return OperateStatusFromServer( new string[] { "BGSAVE" } ); } /// /// 获取服务器的时间戳信息,可用于本地时间的数据同步问题 /// /// 带有服务器时间的结果对象 public OperateResult ReadServerTime( ) { OperateResult times = OperateStringsFromServer( new string[] { "TIME" } ); if (!times.IsSuccess) return OperateResult.CreateFailedResult( times ); long timeTick = long.Parse( times.Content[0] ); DateTime dateTime = new DateTime( 1970, 1, 1, 8, 0, 0 ).AddSeconds( timeTick ); return OperateResult.CreateSuccessResult( dateTime ); } #endregion #region Publish /// /// 将信息 message 发送到指定的频道 channel,返回接收到信息 message 的订阅者数量。 /// /// 频道,和关键字不是一回事 /// 消息 /// 接收到信息 message 的订阅者数量。 public OperateResult Publish( string channel, string message ) { return OperateNumberFromServer( new string[] { "PUBLISH", channel, message } ); } #endregion #region DB Block /// /// 切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。默认使用 0 号数据库。 /// /// 索引值 /// 是否切换成功 public OperateResult SelectDB( int db ) { return OperateStatusFromServer( new string[] { "SELECT", db.ToString( ) } ); } #endregion #region Private Member private string password = string.Empty; // 密码信息 #endregion #region Object Override /// /// 返回表示当前对象的字符串 /// /// 字符串信息 public override string ToString( ) { return $"RedisClient[{IpAddress}:{Port}]"; } #endregion } }