自己动手写Redis客户端(C#实现)3 - GET请求和批量回复

时间:2022-03-31 01:52:12

实现代码(C#)

1、发送GET指令

string keyGet = "SetKeyTest"; // 设置 的key
StringBuilder sbSendGet = new StringBuilder();
sbSendGet.Append("*2\r\n"); // 参数数量 3
string cmdGet = "GET";
sbSendGet.Append("$" + Encoding.UTF8.GetBytes(cmdGet).Length + "\r\n"); // 参数1的长度
sbSendGet.Append(cmdGet + "\r\n");// 参数1( GET指令 ) sbSendGet.Append("$" + Encoding.UTF8.GetBytes(keyGet).Length + "\r\n"); // 参数2的长度
sbSendGet.Append("" + keyGet + "\r\n");// 参数2(GET 的 KEY)
Console.WriteLine("发送的命令:");
Console.Write(sbSendGet.ToString());
byte[] dataGet = Encoding.UTF8.GetBytes(sbSendGet.ToString()); // 把请求转换为byte数组
s.Send(dataGet); // 发送指令

2、接收批量回复

byte[] resultGET = new byte[];
int resultGetLength = s.Receive(resultGET); // 接收回复 // 根据接收到的数据长度重新组装一个结果
byte[] newResultGet = new byte[resultGetLength];
for (int i = ; i < resultGetLength; i++)
{
newResultGet[i] = resultGET[i];
}
string strGetResult = Encoding.UTF8.GetString(newResultGet); // 把结果转换为string
Console.Write("获取的值:"+strGetResult);

3、 结果:

自己动手写Redis客户端(C#实现)3 - GET请求和批量回复

代码重构

1、发送指令

/// <summary>
/// 发送指令
/// </summary>
/// <param name="client"></param>
/// <param name="datas"></param>
/// <returns></returns>
public static string SendCmd(this Socket client, params byte[][] datas) {
client.Send(Encoding.UTF8.GetBytes("*" + datas.Length + "\r\n"));
for (int i = ; i < datas.Length; i++)
{
client.Send(Encoding.UTF8.GetBytes("$" + datas[i].Length));
client.Send(Encoding.UTF8.GetBytes("\r\n"));
client.Send(datas[i]);
client.Send(Encoding.UTF8.GetBytes("\r\n"));
}
return Reply(client);
}

2、接收回复

/// <summary>
/// 接收回复
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
public static string Reply(Socket client) {
BufferedStream s = new BufferedStream(new NetworkStream(client));
int b = s.ReadByte(); // 读取第一个字节
string result;
switch (b)
{
// 状态回复(status reply)的第一个字节是 "+"
case '+':
result = ReadLine(s);
return "+"+result;
// 错误回复(error reply)的第一个字节是 "-"
case '-':
result = ReadLine(s);
throw new Exception(result); // 抛出异常
// 整数回复(integer reply)的第一个字节是 ":"
case ':':
result = ReadLine(s);
return ":" + result;
// 批量回复(bulk reply)的第一个字节是 "$"
case '$':
result = ReadLine(s); // 先读取数据字节数
Console.WriteLine("$"+result);
int count = int.Parse(result);
// 如果被请求的值不存在, 那么批量回复会将特殊值 -1 用作回复的长度值,
if (count == -)
{
return null;
}
result = ReadByLength(s, count);
Console.WriteLine(result);
return result;
// 多条批量回复(multi bulk reply)的第一个字节是 "*"
case '*':
result = ReadLine(s); // 先读取数据行数
Console.WriteLine("*" + result);
int rows = int.Parse(result);
StringBuilder sb = new StringBuilder();
for (int i = ; i < rows; i++)
{
result = ReadLine(s);
sb.AppendLine(result);
result = ReadLine(s);
sb.AppendLine(result);
}
Console.WriteLine(sb); return sb.ToString();
default:
break;
}
return "";
}
/// <summary>
/// 按长度读取
/// </summary>
/// <param name="s"></param>
/// <param name="l"></param>
/// <returns></returns>
public static string ReadByLength(BufferedStream s, long l) {
byte[] bytes = new byte[l];
var r= s.Read(bytes,,(int)l);
return Encoding.UTF8.GetString(bytes);
}
/// <summary>
/// 按行读取
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ReadLine(BufferedStream s)
{
StringBuilder sb = new StringBuilder();
int b = ;
while ((b = s.ReadByte()) != -)
{
if (b == '\r')
{
if ((b = s.ReadByte()) != -)
{
if (b == '\n')
{
break;
}
else
{
sb.Append('\r');
}
}
else
{
break;
} }
sb.Append((char)b);
}
return sb.ToString();
}

3、GET和SET指令

public static bool Set(this Socket client, string key, string value) {
return Set(client, key, Encoding.UTF8.GetBytes(value));
}
public static bool Set(this Socket client, string key, byte[] value)
{
string result = SendCmd(client, Encoding.UTF8.GetBytes("SET"), Encoding.UTF8.GetBytes(key), value);
Console.WriteLine(result);
return result == "+OK"; // 如果+OK 则表示设置成功!
//string
}
public static string Get(this Socket client, string key)
{
return SendCmd(client, Encoding.UTF8.GetBytes("GET"), Encoding.UTF8.GetBytes(key));
//string
}

4、重构后的代码

#region SET
string key = "SetKeyTest"; // 设置 的key
string value = "设置的值"; // 设置的值
var result = s.Set(key, value);
Console.WriteLine(result ? "设置成功!" : "设置失败!"); // 判断设置是否成功
#endregion #region 发送指令Get
string keyGet = "SetKeyTest"; // 设置 的key var resultGet = s.Get(keyGet); // 发送指令
Console.Write("获取的值:" + resultGet);
#endregion

是不是简洁很多???

5、结果

自己动手写Redis客户端(C#实现)3 - GET请求和批量回复

自己动手写Redis客户端(C#实现)3 - GET请求和批量回复的更多相关文章

  1. 自己动手写Redis客户端- Redis协议(1)

    网络层 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 . 客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾. 请求 Redis 服务器接受命令以及命 ...

  2. 自己动手写Redis客户端(C&num;实现)2 - SET请求和状态回复(set)

    Redis请求协议的一般形式: *<参数数量> CR LF $<参数 的字节数量> CR LF <参数 的数据> CR LF ... $<参数 N 的字节数量 ...

  3. 自己动手写Redis客户端(C&num;实现)4 - 整数回复

    整数回复 整数回复就是一个以 ":" 开头, CRLF 结尾的字符串表示的整数. 比如说, ":0\r\n" 和 ":1000\r\n" 都 ...

  4. 从零开始写redis客户端(deerlet-redis-client)之路——第一个纠结很久的问题,restore引发的血案

    引言 正如之前的一篇博文,LZ最近正在从零开始写一个redis的客户端,主要目的是为了更加深入的了解redis,当然了,LZ也希望deerlet客户端有一天能有一席之地.在写的过程当中,LZ遇到了一个 ...

  5. 用C、python手写redis客户端,兼容redis集群 &lpar;-MOVED和-ASK&rpar;,快速搭建redis集群

    想没想过,自己写一个redis客户端,是不是很难呢? 其实,并不是特别难. 首先,要知道redis服务端用的通信协议,建议直接去官网看,博客啥的其实也是从官网摘抄的,或者从其他博客抄的(忽略). 协议 ...

  6. 手写redis客户端

    一.RESP通信协议 Redis Serialization Protocol (Redis序列化协议). 特点:容易实现.解析快.可读性强 以\r\n分割数据. 二.撸代码 package com. ...

  7. 用BIO手写实现Redis客户端的探究&lpar;拒绝Jedis&rpar;

    在Redis的使用过程中,大多数人都是使用现成的客户端,如Jedis,Redisson,Lettuce.因此本文研究用BIO的方式手写Redis客户端尝试,对遇到的问题进行探究及总结. Redis通讯 ...

  8. 解决ASP&period;NET中Redis 每小时6000次访问请求的问题

    原文:解决ASP.NET中Redis 每小时6000次访问请求的问题 虽然ServiceStack v4是商业支持的产品,但我们也允许免费使用小型项目和评估目的.上面的NuGet包中包含可以使用许可证 ...

  9. 学习T-io框架,从写一个Redis客户端开始

    前言   了解T-io框架有些日子了,并且还将它应用于实战,例如 tio-websocket-server,tio-http-server等.但是由于上述两个server已经封装好,直接应用就可以.所 ...

随机推荐

  1. Python 之 装饰器的写法

    普通装饰器 1. 不带参数的普通装饰器 from functools import wraps def use_logging(func): @wraps(func) # 使得装饰器函数和原函数有一样 ...

  2. Windows 8&period;1 系统ISO镜像下载或自Win8应用商店升级方法

    1)下载 -- 面向全体用户的Win8.1预览版ISO镜像下载(28日开放): 安装时请输入微软官方提供给大家的产品密钥:NTTX3-RV7VB-T7X7F-WQYYY-9Y92F. 64位简体中文版 ...

  3. MySQL 分组

    MySQL GROUP BY 语句 GROUP BY 语句根据一个或多个列对结果集进行分组. 在分组的列上我们可以使用 COUNT, SUM, AVG,等函数. GROUP BY 语法 SELECT ...

  4. Android 自学之基本界面组件&lpar;下&rpar;

    按钮(Button)与图片按钮(ImageButton)组件的功能和用法 Button继承了TextView,ImageButton继承了Button.不管是Button还是ImageButton,他 ...

  5. android通过服务实现消息推送

    这里运用到的andorid知识模块主要有Notification和Service,和一个android-async-http-master开源框架 android项目中,有时会有这样一种需求:客户每隔 ...

  6. php获取音悦台视频

    <?php $url=isset($_GET['url'])?trim($_GET['url']):''; $url = "http://v.yinyuetai.com/video/6 ...

  7. 在&period;net中怎么解析json串 &lbrack;Error reading JObject from JsonReader&period; Current JsonReader item is not an obj&rsqb;

    编辑时间:2017-05-10,增加一种转化list的方法 一.以前知道一种解析json串的方法,觉得有点麻烦.就从别的地方搜到了另一种 string json = vlt.getlist(); JO ...

  8. Docker5之Deploy your app

    Make sure you have published the friendlyhello image you created by pushing it to a registry. We’ll ...

  9. MFC message routine

    现在维护的一个软件还是用mfc写的,最近被要加入一个功能弄得焦头烂额.主要现象就是加入的菜单的响应函数没被call到 上网搜索,在官方网站找到了不少资料 主要链接如下 https://msdn.mic ...

  10. CAShapeLayer的使用&lbrack;2&rsqb;

    CAShapeLayer的使用[2] CAShapeLayer支持的动画类型有如下这些. ------------------------------------------------------- ...