使用 DotNetty 实现 Redis 的一个控制台应用程序

上图:Demo 跑出来的结果如图

蓝色的是cmd 的命令,黑色的是C#写的控制台程序。红色箭头部分是 redis 命令

0. Netty是Java生态圈的一个重要组件。个人认为JAVA繁荣于.NET 生态的很重要一个原因,就是缺少了这样一个NIO框架。JAVA的游戏开发,少不得使用Netty.

原生Socker编程,犹如一辆绿皮火车。Netty无疑是高铁般的存在。

1.学习DotNetty很久。从DotNetty 0.4版本。到现在的0.48版本。自己实现一个C/S端的例子。还没有太好的想法去实现。

    今天看到haifeiWu 的高作《Netty 源码中对 Redis 协议的实现》,遂想跟着实现一个。

    所以,才有了今天的Demo.

    是的,它还只是一个Demo.并不能取代StackExchange.Redis。

2   RESP 是 Redis 序列化协议的简写。它是一种直观的文本协议,优势在于实现非常简单,解析性能极好。

  Redis 协议将传输的结构数据分为 5 种最小单元类型,单元结束时统一加上回车换行符号\r\n,来表示该单元的结束。

  单行字符串 以 + 符号开头。

  多行字符串 以 $ 符号开头,后跟字符串长度。

  整数值 以 : 符号开头,后跟整数的字符串形式。

  错误消息 以 - 符号开头。

  数组 以 * 号开头,后跟数组的长度。

  关于 RESP 协议的具体介绍感兴趣的小伙伴请移步 haifeiWu 的另一篇文章Redis协议规范(译文)

以上第二点是摘抄自 haifeiWu中的介绍

Demo 开始

1,定义枚举 RedisMessageType

 1 internal enum RedisMessageType:byte
 2     {
 3         /// <summary>
 4         /// 以 + 开头的单行字符串
 5         /// </summary>
 6         SimpleString = 43,
 7 
 8         /// <summary>
 9         ///  以 - 开头的错误信息
10         /// </summary>
11         Error = 45,
12         /// <summary>
13         /// 以 : 开头的整型数据INTEGER
14         /// </summary>
15         Integer = 58,
16         /// <summary>
17         /// 以 $ 开头的多行字符串
18         /// </summary>
19         BulkString = 36,
20 
21         /// <summary>
22         /// 以 * 开头的数组
23         /// </summary>
24         ArrayHeader = 42
25     }
View Code

2,定义RedisObject   并定义了虚拟的方法 WriteBuffer

 1 public class RedisObject
 2     {
 3         public virtual void WriteBuffer(IByteBuffer output)
 4         {
 5         }
 6     }
 7 
 8 public class RedisCommon : RedisObject
 9     {
10         public RedisCommon()
11         {
12             Commond = new List<string>();
13         }
14         public List<string> Commond { get; set; }
15         public override void WriteBuffer(IByteBuffer output)
16         {
17             //请求头部格式, *<number of arguments>\r\n
18             //const string headstr = "*{0}\r\n";
19             //参数信息       $<number of bytes of argument N>\r\n<argument data>\r\n
20             //const string bulkstr = "${0}\r\n{1}\r\n";
21             StringBuilder stringBuilder = new StringBuilder();
22             stringBuilder.AppendFormat("*{0}\r\n",Commond.Count);
23             foreach (var item in Commond)
24             {
25                 stringBuilder.AppendFormat("${0}\r\n{1}\r\n",item.Length,item);
26             }
27             //*1\r\n$4\r\nPING\r\n
28             byte[] bytes = Encoding.UTF8.GetBytes(stringBuilder.ToString());
29             output.WriteBytes(bytes);
30         }
31     }
View Code

3,定义RedisEncoder 编码器, 它集成了MessageToByteEncoder<T>方法。主要是将RedisObject,写到IByteBuffer里面。

public class RedisEncoder:DotNetty.Codecs.MessageToByteEncoder<RedisObject>
    {
        protected override void Encode(IChannelHandlerContext context, RedisObject message, IByteBuffer output)
        {
            message.WriteBuffer(output);
            //context.WriteAndFlushAsync(output);
        }
    }

  

4,定义 RedisDecoder 解码器,它继承了 ByteToMessageDecoder。

  ByteToMessageDecoder 是需要自己实现解决粘包,拆包的。比较低级别,但是灵活。

  DotNetty 还有其他比较高级的解码器。

  比如 MessageToMessageDecoder, DatagramPacketDecoder,LengthFieldBasedFrameDecoder,LineBasedFrameDecoder,ReplayingDecoder,DelimiterBasedFrameDecoder,StringDecoder。

  在蒋老师的《Netty权威指南》一书中,都能学习到。

  

6.定义 RedisHandle Handler ,他继承了SimpleChannelInboundHandler 的方法。用来接收解码器之后解出来的RedisObJect对象。

public class RedisHandle : SimpleChannelInboundHandler<RedisObject>
    {
        protected override void ChannelRead0(IChannelHandlerContext ctx, RedisObject msg)
        {
            if (msg is ReidsString)
            {
                ReidsString reidsString = (ReidsString)msg;
                Console.WriteLine(reidsString.Content);
            }
        }
    }

  

猜你喜欢

转载自www.cnblogs.com/ruxia/p/9477389.html