接上篇c#實現redis客戶端(一),從新整理些了下。html
閱讀目錄:git
背景:由於有地方要用,而又沒找到對sentinel良好支持的Net客戶端,因此就簡單重寫了個。github
目標:儘量的簡單,輕量級,不進行過分的封裝,使用方便。redis
代碼說明:
c#
1. 與Redis服務端的Socket通訊、協議格式封裝。在RedisBaseClient裏
多線程
2. 只對Set、Get封裝,暴露出Send接口。在RedisCommand裏面添加本身想要的支持。併發
var info = rcClient.Send(RedisCommand.INFO);
3. RedisBaseClient是通訊層。 若是擴展其餘用途繼承便可,好比RedisPubSub:RedisBaseClient,RedisSentinel:RedisBaseClientsocket
4. 供上層良好調用的話,能夠作成partial類擴展redisclient。好比RedisClient.Stringide
5. 訂閱的監聽使用while的,可在觸發事件裏面作阻塞。post
6. PoolRedisClient池的實現使用ConcurrentStack,僅達到了複用socket鏈接的目的。
7. 支持socket重連,作法是關閉舊鏈接,從新創建新socket。
8. 多個命令使用管道實現。見set實現
後續思路:
一:PoolRedisClient池裏面鏈接的釋放問題?
1. 使用using
2. 不用使用using,會自動檢測並回收 。
不作成自動檢測的話,就會出現鏈接沒法釋放的問題,總會有人忘記釋放的,因此要優化成1+2結合的方式。
二:client池和socket池分離,socket單獨作一個池? 還在考慮中。
命令執行流程圖、解決方案圖、類圖。
[TestMethod, TestCategory("Server")] public void Redis_PassWord() { using (var rcClient = new RedisClient(new RedisConfiguration() { Host = ip, Port = 6381, PassWord = "123465" })) { var info = rcClient.Send(RedisCommand.INFO); Debug.Write(info.ToString()); } }
[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", 20001)) { 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("*"); }
[TestMethod, TestCategory("poolRedisclient")] public void GetClient_Test() { PoolRedisClient prc = new PoolRedisClient(new PoolConfiguration() { Host = ip, Port = port, MaxClients = 100 }); 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 = 100 }); Parallel.For(0, 1000, new ParallelOptions() {MaxDegreeOfParallelism = 100}, (index, item) => { using (var client = prc.GetClient()) { Thread.Sleep(100); 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 = 100 }); object info2; using (var client = prc.GetClient()) { var result = client.Set("PoolClient_TimeOut_Test", "PoolClient_TimeOut_Test"); Thread.Sleep(15000); 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(0, 1000, new ParallelOptions() {MaxDegreeOfParallelism = 100}, (index, item) => { var t = new Thread(() => { Thread.Sleep(1000); object info2; using (var client = prc.GetClient()) { client.Set("Parallel_PoolClient_Test" + index, "Parallel_PoolClient_Test"); Thread.Sleep(15000); info2 = client.Get("Parallel_PoolClient_Test" + index); } Assert.AreEqual(info2.ToString(), "Parallel_PoolClient_Test"); }); t.Start(); }); Thread.Sleep(20000); prc.Dispose(); }
[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", 10); var info1 = rcClient.Get("Set_key_Expire"); Assert.AreEqual(info1.ToString(), "Set_key_Expire"); Thread.Sleep(11000); var info2 = rcClient.Get("Set_key_Expire"); Assert.AreEqual(info2, null); } }
開源地址:https://github.com/mushroomsir/HRedis 有須要的同窗,能夠參考下。
Hredis後續會跟實際需求來寫,若是有更好的實現思路,歡迎一塊兒交流。