自己动手写Redis客户端(C#实现)3 - GET请求和批量回复
实现代码(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、 结果:

代码重构
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客户端- Redis协议(1)
网络层 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 . 客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾. 请求 Redis 服务器接受命令以及命 ...
- 自己动手写Redis客户端(C#实现)2 - SET请求和状态回复(set)
Redis请求协议的一般形式: *<参数数量> CR LF $<参数 的字节数量> CR LF <参数 的数据> CR LF ... $<参数 N 的字节数量 ...
- 自己动手写Redis客户端(C#实现)4 - 整数回复
整数回复 整数回复就是一个以 ":" 开头, CRLF 结尾的字符串表示的整数. 比如说, ":0\r\n" 和 ":1000\r\n" 都 ...
- 从零开始写redis客户端(deerlet-redis-client)之路——第一个纠结很久的问题,restore引发的血案
引言 正如之前的一篇博文,LZ最近正在从零开始写一个redis的客户端,主要目的是为了更加深入的了解redis,当然了,LZ也希望deerlet客户端有一天能有一席之地.在写的过程当中,LZ遇到了一个 ...
- 用C、python手写redis客户端,兼容redis集群 (-MOVED和-ASK),快速搭建redis集群
想没想过,自己写一个redis客户端,是不是很难呢? 其实,并不是特别难. 首先,要知道redis服务端用的通信协议,建议直接去官网看,博客啥的其实也是从官网摘抄的,或者从其他博客抄的(忽略). 协议 ...
- 手写redis客户端
一.RESP通信协议 Redis Serialization Protocol (Redis序列化协议). 特点:容易实现.解析快.可读性强 以\r\n分割数据. 二.撸代码 package com. ...
- 用BIO手写实现Redis客户端的探究(拒绝Jedis)
在Redis的使用过程中,大多数人都是使用现成的客户端,如Jedis,Redisson,Lettuce.因此本文研究用BIO的方式手写Redis客户端尝试,对遇到的问题进行探究及总结. Redis通讯 ...
- 解决ASP.NET中Redis 每小时6000次访问请求的问题
原文:解决ASP.NET中Redis 每小时6000次访问请求的问题 虽然ServiceStack v4是商业支持的产品,但我们也允许免费使用小型项目和评估目的.上面的NuGet包中包含可以使用许可证 ...
- 学习T-io框架,从写一个Redis客户端开始
前言 了解T-io框架有些日子了,并且还将它应用于实战,例如 tio-websocket-server,tio-http-server等.但是由于上述两个server已经封装好,直接应用就可以.所 ...
随机推荐
- LOJ#2087 国王饮水记
解:这个题一脸不可做... 比1小的怎么办啊,好像没用,扔了吧. 先看部分分,n = 2简单,我会分类讨论!n = 4简单,我会搜索!n = 10,我会剪枝! k = 1怎么办,好像选的那些越大越好啊 ...
- spring问题
1.The matching wildcard is strict ,but no declaration can be found for element 'tx:annotation-driven ...
- ORA-00923: FROM keyword not found where expected(单双引号)
1.前提 在学习oracel的过程中遇到的一个关于单双引号的问题 备注一下 2.学习过程中创建表语句是这样的 create table DEPT_DML --部门表( DEPT_NO NUMBER(8 ...
- 第一周java学习总结
学号 20175206 <Java程序设计>第一周学习总结 教材学习内容总结 第一章是关于JAVA入门的注意事项: 第一章主要按照顺序讲了JAVA的地位,诞生,特点,JDK的安装,一些ja ...
- loadrunner 添加集合点和添加压力机
loadrunner 添加集合点和添加压力机 一.添加集合点: 1.在脚本中右键insert--rendezvous (集合点一定要添加在事务的外面,否则影响事务准确性) 2.创建controller ...
- 条件随机场(conditional random field,CRF)模型初探
0. 引言 0x1:为什么会有条件随机场?它解决了什么问题? 在开始学习CRF条件随机场之前,我们需要先了解一下这个算法的来龙去脉,它是在什么情况下被提出的,是从哪个算法演进而来的,它又解决了哪些问题 ...
- 一次 ElasticSearch 搜索优化
一次 ElasticSearch 搜索优化 1. 环境 ES6.3.2,索引名称 user_v1,5个主分片,每个分片一个副本.分片基本都在11GB左右,GET _cat/shards/user 一共 ...
- Eclipse使用JDBC小案例
JDBC(Java Database Connectivity:Java访问数据库的解决方案)定义一套标准接口,即访问数据库的通用API,不同数据库厂商根据各自数据的特点去实现这些接口. JDBC是J ...
- spark基础知识(1)
一.大数据架构 并发计算: 并行计算: 很少会说并发计算,一般都是说并行计算,但是并行计算用的是并发技术.并发更偏向于底层.并发通常指的是单机上的并发运行,通过多线程来实现.而并行计算的范围更广,他是 ...
- GitHub:本地项目上传与团队协作
第一部分:我的本次作业成果 我自己个人的github地址是:colintz的个人仓库 我们开发团队小组的github地址是:小组3集中营 第二部分:强烈推荐的github资源 对于和我一样,初次接触g ...