接上篇c#实现redis客户端(一),重新整理些了下。

阅读目录:

  1. 项目说明
  2. Hredis设计图
  3. 单元测试场景
  4. 总结

项目说明

背景:因为有地方要用,而又没找到对sentinel良好支持的Net客户端,所以就简单重写了个。

目标:尽可能的简单,轻量级,不进行过度的封装,使用方便。

代码说明:

1. 与Redis服务端的Socket通信、协议格式封装。在RedisBaseClient里 

2. 只对Set、Get封装,暴露出Send接口。在RedisCommand里面添加自己想要的支持。

var info = rcClient.Send(RedisCommand.INFO);

3.  RedisBaseClient是通信层。 如果扩展其他用途继承即可,比如RedisPubSub:RedisBaseClient,RedisSentinel:RedisBaseClient

4.  供上层良好调用的话,可以做成partial类扩展redisclient。比如RedisClient.String

5.  订阅的监听使用while的,可在触发事件里面做阻塞。

6.  PoolRedisClient池的实现使用ConcurrentStack,仅达到了复用socket连接的目的。

7.  支持socket重连,做法是关闭旧连接,重新建立新socket。

8.  多个命令使用管道实现。见set实现

后续思路:

      一:PoolRedisClient池里面连接的释放问题?

1. 使用using

2. 不用使用using,会自动检测并回收 。

不做成自动检测的话,就会出现连接无法释放的问题,总会有人忘记释放的,所以要优化成1+2结合的方式。

二:client池和socket池分离,socket单独做一个池? 还在考虑中。

Hredis设计图

命令执行流程图、解决方案图、类图。

  

单元测试场景

一. Info命令通信、密码配置。

 [TestMethod, TestCategory("Server")]
public void Redis_PassWord()
{
using (var rcClient = new RedisClient(new RedisConfiguration()
{
Host = ip,
Port = ,
PassWord = ""
}))
{
var info = rcClient.Send(RedisCommand.INFO);
Debug.Write(info.ToString());
}
}

二. 普通订阅,及模式匹配订阅。这里订阅的是Sentinel事件信息。

        [TestMethod, TestCategory("PushSub")]
public void Subscribe_Sentinel_Test()
{
using (RedisPubSub rsc = new RedisPubSub("127.0.0.1", 20001))
{
rsc.SubscriptionReceived += rsc_SubscriptionReceived;
//rsc.Subscribe("+sdown");
}
}
[TestMethod, TestCategory("PushSub")]
public void PSubscribe_Sentinel_Test()
{
using (RedisPubSub rsc = new RedisPubSub("127.0.0.1", ))
{
rsc.SubscriptionReceived += rsc_SubscriptionReceived;
// rsc.PSubscribe("*");
}
} private void rsc_SubscriptionReceived(object sender, object args)
{
if (args is object[])
{
var list = args as object[];
foreach (var o in list)
{
Debug.Write("\r\n" + o.ToString());
}
}
else
{
Debug.Write("\r\n" + args.ToString());
} var sr = sender as RedisPubSub;
sr.UnSubscribe("*");
}

三.  client连接池、Parallel并发模拟。

  [TestMethod, TestCategory("poolRedisclient")]
public void GetClient_Test()
{
PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration()
{
Host = ip,
Port = port,
MaxClients =
});
using (var client = prc.GetClient())
{
client.Set("GetClient_Test", "GetClient_Test"); var info2 = client.Get("GetClient_Test"); Assert.AreEqual(info2.ToString(), "GetClient_Test");
}
prc.Dispose();
}
        [TestMethod, TestCategory("poolRedisclient")]
public void Parallel_PoolClient_Test()
{
PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration()
{
Host = ip,
Port = port,
MaxClients =
});
Parallel.For(, , new ParallelOptions() {MaxDegreeOfParallelism = }, (index, item) =>
{
using (var client = prc.GetClient())
{
Thread.Sleep();
client.Set("Parallel_PoolClient_Test" + index, "Parallel_PoolClient_Test"); var info2 = client.Get("Parallel_PoolClient_Test" + index); Assert.AreEqual(info2.ToString(), "Parallel_PoolClient_Test");
}
});
prc.Dispose();
}

三.  超时重连、多线程并发超时重连。

        [TestMethod, TestCategory("poolRedisclient")]
public void PoolClient_TimeOut_Test()
{
PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration()
{
Host = ip,
Port = port,
MaxClients =
});
object info2;
using (var client = prc.GetClient())
{
var result = client.Set("PoolClient_TimeOut_Test", "PoolClient_TimeOut_Test");
Thread.Sleep();
info2 = client.Get("PoolClient_TimeOut_Test"); }
Assert.AreEqual(info2.ToString(), "PoolClient_TimeOut_Test"); prc.Dispose();
}
  [TestMethod, TestCategory("poolRedisclient")]
public void Thread_PoolClient_Test()
{
PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration()
{
Host = ip,
Port = port
});
Parallel.For(, , new ParallelOptions() {MaxDegreeOfParallelism = }, (index, item) =>
{
var t = new Thread(() =>
{
Thread.Sleep();
object info2;
using (var client = prc.GetClient())
{
client.Set("Parallel_PoolClient_Test" + index, "Parallel_PoolClient_Test"); Thread.Sleep(); info2 = client.Get("Parallel_PoolClient_Test" + index);
}
Assert.AreEqual(info2.ToString(), "Parallel_PoolClient_Test");
});
t.Start();
});
Thread.Sleep();
prc.Dispose();
}

四. String类型添加、过期时间添加。

[TestMethod, TestCategory("String")]
public void Set_Get_key()
{
using (var rcClient = new RedisClient(ip, port))
{
rcClient.Set("Set_Get_key", "Set_Get_key");
var info2 = rcClient.Get("Set_Get_key");
Assert.AreEqual(info2.ToString(), "Set_Get_key");
}
}
  [TestMethod, TestCategory("String")]
public void Set_key_Expire()
{
using (var rcClient = new RedisClient(ip, port))
{
rcClient.Set("Set_key_Expire", "Set_key_Expire", ); var info1 = rcClient.Get("Set_key_Expire"); Assert.AreEqual(info1.ToString(), "Set_key_Expire"); Thread.Sleep();
var info2 = rcClient.Get("Set_key_Expire"); Assert.AreEqual(info2, null); }
}

总结

开源地址:https://github.com/mushroomsir/HRedis  有需要的同学,可以参考下。

Hredis后续会跟实际需求来写,如果有更好的实现思路,欢迎一起交流。

Redis系列(二)-Hredis客户端设计及开源的更多相关文章

  1. Redis系列(二):Redis的数据类型及命令操作

    原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...

  2. Redis系列(二):Redis的5种数据结构及其常用命令

    上一篇博客,我们讲解了什么是Redis以及在Windows和Linux环境下安装Redis的方法, 没看过的同学可以点击以下链接查看: Redis系列(一):Redis简介及环境安装. 本篇博客我们来 ...

  3. Redis系列(二)--分布式锁、分布式ID简单实现及思路

    分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...

  4. Redis系列二之事务及消息通知

    一.事务 Redis中的事务是一组命令的集合.一个事务中的命令要么都执行,要么都不执行. 1.事务简介 事务的原理是先将一个事务的命令发送给Redis,然后再让Redis依次执行这些命令.下面看一个示 ...

  5. Redis系列二:reids介绍

    一.什么是redis.redis有哪些特性.redis有哪些应用场景.redis的版本 1. 什么是redis redis是一种基于键值对(key-value)数据库,其中value可以为string ...

  6. redis系列二: linux下安装redis

    下面介绍在Linux环境下,Redis的安装与配置 一. 安装 1.首先上官网下载Redis 压缩包,地址:http://redis.io/download 下载稳定版3.0即可. 2.通过远程管理工 ...

  7. Redis系列二 - 数据结构

    前言 redis作为我们开发的一大神器,我们接触肯定不会少,但是很多同学也许只会存储String类型的值,这是非常不合理的.在这里,将带大家认识Redis的5中数据结构. 1.问:Redis有那些数据 ...

  8. Redis系列二(yum切换为网易163)

    这个可能和Redis没有直接的关系... 是我在yum install的时候发现centos的yum实在是太慢,上网查了下.网易163有个yum镜像,为了让CentOS6使用速度更快的YUM更新源,可 ...

  9. Redis系列二 Redis数据库介绍

    1.SELECT命令 通过查看配置文件可以知道Redis默认有17个库,从0-16. 默认是在0号库.选择库使用SELECT <dbid>命令.例如选择0号库  SELECT 0 2.DB ...

随机推荐

  1. fullPage.js学习笔记

    中秋节,一个人呆着,挺无聊的,还是学习最有趣,不论是什么,开阔视野都是好的. 参考网址:http://www.dowebok.com/77.html  上面有详细介绍及案例展示,很不错哦,可以先去看看 ...

  2. 进击的Python【第二章】:Python基础(二)

    Python基础(二) 本章内容 数据类型 数据运算 列表与元组的基本操作 字典的基本操作 字符编码与转码 模块初探 练习:购物车程序 一.数据类型 Python有五个标准的数据类型: Numbers ...

  3. react native 刷新机制----通知

    在项目中,不知道大家有没有遇到这样的一个问题,比如说有两个页面A,B.A页面中有某个按钮点击后可以跳转到B页面,现在有一个需求就是,我在B页面中做了某些操作,然后点击回退按钮,回到A页面,A页面中的数 ...

  4. 1208PHP语句

    var_dump(empty($a)); 判断变量是否为空var_dump(isset($a)); 判断变量是否定义 unset(变量); 删除变量 &代表变量的地址:$a = ;$b = & ...

  5. C#ListBox对Item进行重绘,包括颜色

    别的不多说了,上代码,直接看 首先设置这行,或者属性窗口设置,这样才可以启动手动绘制,参数有三个 Normal: 自动绘制 OwnerDrawFixed:手动绘制,但间距相同 OwnerDrawVar ...

  6. 【oracle】union、union all、intersect、minus 的用法及区别

    一.union与union all 首先建两个view create or replace view test_view_1 as as c from dual union as c from dua ...

  7. unity 利用ugui 制作技能冷却效果

    using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; ...

  8. 【生活没有希望】hdu1166敌兵布阵 线段树

    线段树水题刷刷,生活没有希望 最近看到代码跟树状数组差不多短的非递归线段树,常数也很小——zkw线段树 于是拿道水题练练手 短到让人身无可恋 ;pos;pos/=) a[pos]+=x;} ,ans= ...

  9. ASCII和16进制对照表

    十六进制代码 MCS 字符或缩写 DEC 多国字符名 ASCII 控制字符 1 00 NUL 空字符 01 SOH 标题起始 (Ctrl/A) 02 STX 文本起始 (Ctrl/B) 03 ETX ...

  10. bootstrap之CDN

    bootstrap之CDN CDN是Content Delivery Network的缩写,简单的说就是Bootstrap把自己的css.Js等文件托管到某一个网络服务器上使用时调用.如果与Inter ...