当前位置: 首页 > news >正文

Linux下C/C++ redis协议(RESP)解析

Redis是一个开源的内存键值数据存储,最常用作主数据库、缓存、消息代理和队列。Redis提供了亚毫秒的响应时间,在游戏、金融科技、广告技术、社交媒体、医疗保健和物联网等行业实现了快速而强大的实时应用。

Redis连续五年成为开发人员最喜爱的数据库。开发人员喜欢Redis,因为它的易用性、性能和可扩展性。Redis客户端可用于各种流行的现代编程语言。再加上性能优势,Redis成为缓存、会话管理、游戏、欺诈检测、排行榜、实时分析、地理空间索引、拼车、社交媒体和流媒体应用程序最受欢迎的选择。

使用CLI探索Redis

外部程序使用TCP套接字和Redis特定的协议与Redis进行通信。该协议在Redis客户端库中实现,用于不同的编程语言。然而,为了简化Redis的黑客攻击,Redis提供了一个命令行实用程序,可以用来向Redis发送命令。这个程序叫做redis-cli。

这里我们先看看redis服务器是否开启。
要检查Redis是否正常工作,首先要做的是使用reds-cli发送一个PING命令:

运行reds-cli,后跟一个命令名及其参数,将此命令发送到本地主机6379端口上运行的redis实例。可以更改reds-cli使用的主机和端口,只需尝试–help选项即可检查使用情况信息。

另一种运行redis-cli的方法是不带参数:程序将以交互模式启动。您可以键入不同的命令并查看它们的答复。

保护好你的Redis

默认情况下,Redis绑定到所有接口,并且根本没有身份验证。如果你在一个非常可控的环境中使用Redis,与外部互联网分离,通常与攻击者分离,那没关系。

然而,如果一个未经保护的Redis暴露在互联网上,这将是一个巨大的安全问题。如果您不能100%确定您的环境是否正确安全,请检查以下步骤以使Redis更安全,这些步骤是为了提高安全性而登记的。

1.确保Redis用于监听连接的端口(默认情况下为6379,如果您在集群模式下运行Redis,则为16379,Sentinel为26379)已防火墙,因此无法从外部联系Redis。2.使用设置了bind指令的配置文件,以确保Redis只侦听您正在使用的网络接口。例如,如果您只是从同一台计算机本地访问Redis,则仅使用环回接口(127.0.0.1),依此类推。3.使用requirepass选项可以添加额外的安全层,以便客户端需要使用AUTH命令进行身份验证。4.如果您的环境需要加密,请使用spiped或其他SSL隧道软件来加密Redis服务器和Redis客户端之间的流量。

请注意,在没有任何安全性的情况下暴露在互联网上的Redis实例很容易被利用,所以请确保您理解以上内容,并至少应用一个防火墙层。防火墙就位后,尝试从外部主机连接reds-cli,以证明该实例实际上是不可访问的。

从应用程序(hiRedis)中使用Redis

当然,仅仅从命令行界面使用Redis是不够的,因为目标是从应用程序中使用它。为了做到这一点,您需要下载并安装适用于您的编程语言的Redis客户端库。

hiRedis使用方法一般顺序为先用 redisConnect 连接数据库,然后用 redisCommand 执行命令,执行完后用 freeReplyObject 来释放redisReply对象,最后用 redisFree 来释放整个连接。

...
int main(int argc, char **argv) 
{/* 连接到redis */...redisContext *c = redisConnect(hostname,port);struct timeval timeout = { 1, 500000 }; // 1.5 secondsif (isunix) {c = redisConnectUnixWithTimeout(hostname, timeout);} else {c = redisConnectWithTimeout(hostname, port, timeout);}if (c == NULL || c->err) {if (c) {printf("Connection error: %s\n", c->errstr);redisFree(c);} else {printf("Connection error: can't allocate redis context\n");}exit(1);}printf("Connected to redis\n");// redisFree(c);/* 2 - PING server */redisReply *reply;  /* 临时答复指针 */reply = redisCommand(c,"PING");printf("PING: %s\n", reply->str);/* 3 - Set a key */reply = redisCommand(c,"SET %s %s", "foo", "hello world");printf("SET %s %s \t| %s\n", "foo", "hello world", reply->str);freeReplyObject(reply);     // 释放回复对象/* 3 - Get a key */reply = redisCommand(c,"GET %s","foo");printf("GET %s \t\t| ","foo");printf("%s\n",reply->str);freeReplyObject(reply);/* Set a key using binary safe API */// reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);// printf("SET (binary API): %s\n", reply->str);// freeReplyObject(reply);redisFree(c);return 0;
}

运行结果:

我们也可以使用 nc 命令来替代 redis-cli 命令行:

什么是 RESP?

Redis 的客户端和服务端之间采取了一种独立名为 RESP(REdis Serialization Protocol) 的协议。通过 tcp流式套接字来进行通讯,为了 防止粘包 因此命令或数据均以 \r\n (CRLF) 结尾,然后根据解析规则解析相应信息。

RESP协议可以序列化多种类型,比如Simple Strings(简单字符串),Errors(错误类型),Integers(整形),Bulk Strings(批量串)和Arrays(数组),但此协议只适用于Redis客户端-服务端之间的通信,Redis集群中节点间通信使用的另一种协议。

RESP协议说明

RESP协议是在Redis 1.2中引入的,但它成为了与Redis 2.0中的Redis服务器通信的标准方式。这是所有Redis客户端都要遵循的协议,我们甚至可以基于此协议,开发实现自己的Redis客户端。

RESP在Redis中用作请求-响应协议的方式如下:

1.客户端将命令作为Bulk Strings的RESP数组发送到Redis服务器。
2.服务器根据命令实现回复一种RESP类型。
3.在RESP中,某些数据的类型取决于第一个字节:+代表简单字符串(Simple Strings)比如OK,PONG(对应客户端的PING命令)-代表错误类型(Errors):代表整型(Integers)$代表多行字符串(Bulk Strings)*代表数组(Arrays)
此外,RESP能够使用稍后指定的Bulk Strings或Array的特殊变体来表示Null值。
在RESP中,协议的不同部分始终以“\r\n”(CRLF)结束。

RESP抓包验证

我们知道,Redis客户端与server端通信,本身就是基于tcp的一个Request/Response模式。我们不妨用网络抓包工具,拦截客户端与server端传输的数据、一探究竟。抓包使用tcpdump命令,具体参数这里就不多说了,使用的命令是:

tcpdump host 127.0.0.1 and port 6379 -i lo -w redis-packet-test.cap

抓取的结果保存在redis-packet-test.cap,分析工具使用Wireshark,在分析之前,先说下客户端与服务端交互的命令:

1.info,返回redis服务端的相关信息
2.set abc 111,服务端响应OK
3.get abc,返回111
4.lpush abclist 1 2 3,返回 9
5.ee,这是个错误命令,主要看下服务端返回的错误数据格式
接下来我们结合数据包分析下:

redis-cli:

TCP三次握手建立连接的

PSH是发送数据,ACK是响应.
在这里插入图片描述

首先发送的命令是info,先看右边部分,可以看到一开始是*1:表示长度为1的数组,后边的··对应左边是0d 0a,其实就是\r\n的16进制表示形式,然后后边$4:代表长度为4的Bulk Strings,也就是info,后边紧跟着info。
info命令返回数据包:$1924:长度为1924的Bulk Strings,后边便是服务器相关信息

set abc 111命令:*3:长度为3的数组,后边是数组里的3个元素:$3··set(长度为3的Bulk Strings)、$3··xfh、$3··111
在这里插入图片描述返回数据:+OK(代表简单字符串‘OK’)简单字符串一般是服务器状态相关,比如’OK’、‘PONG’等;而Bulk Strings可以包含任何内容(比如换行符、控制符)

命令lpush abclist 1 2 3:看到这相信大家都已经明白了,*5代表长度为5的数组,后边紧跟着5个Bulk Strings lpush、xfhlist、1、2、3,而且每个元素的前边都有长度,分别是$5、$7、$1、$1、$1
在这里插入图片描述返回::9(表示整形数据9)

命令ff,这是个错误命令,redis中没有这个命令,应该返回语法错误


返回:发现前缀是-,对应RESP协议中的错误类型,后边紧跟着ERR unknown command ‘ff’


Linux下C/C++ RESP协议解析

...
int query_parser(const u_char* pkt_data, unsigned int data_len, char **query)
{
...
}
int resp_parser(const u_char* pkt_data, unsigned int data_len, char **resp)
{
...
}
...
void packetHandle(u_char* arg, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
...if ( !pkt_data ){printf ("Didn't grab packet!/n");exit (1);}if (header->caplen < header->len) return;pehdr = (struct ether_header*)pkt_data;pkt_data += *linkhdrlen;piphdr = (struct ip*)pkt_data;pkt_data += IP_HL(piphdr);data_len = ntohs(piphdr->ip_len) - IP_HL(piphdr);switch(piphdr->ip_p){case IPPROTO_TCP:ptcphdr = (struct tcphdr*)pkt_data;data_len = data_len - TCP_OFF(ptcphdr);pkt_data += TCP_OFF(ptcphdr);strcpy(sip, inet_ntoa(piphdr->ip_src));strcpy(dip, inet_ntoa(piphdr->ip_dst));sport = ntohs(ptcphdr->source);dport = ntohs(ptcphdr->dest);break;default:data_len = 0;pkt_data = NULL;break;}if (data_len == 0 || pkt_data == NULL ) return;...signal(SIGINT, bailout);signal(SIGTERM, bailout);signal(SIGQUIT, bailout);
}   ...
int main(int argc, char **argv)
{
...while ((i = getopt(argc, argv, "hi:p:")) != -1) {switch(i){case 'h':Usage();return -1;break;case 'i':option.device = optarg;break;case 'p':option.port = atoi(optarg);break;default:break;}}sprintf(option.bufstr, "port %d", option.port);char *d = getenv("jdebug");if ( d != NULL &&  !strcmp(d, "true")) debug = 1;dbg("debug mode\n");if((pHandle = init_pcap_t(option.device, option.bufstr))){sniff_loop(pHandle, (pcap_handler)packetHandle);}    
...}

运行结果:

If you need the complete source code, please add the WeChat number (c17865354792)

总结

Redis 基于 RESP (Redis Serialization Protocal)协议来完成客户端和服务端通讯的。RESP 本质是一种文本协议,实现简单、易于解析。底层采用的是TCP的连接方式,通过tcp进行数据传输,然后根据解析规则解析相应信息。

Welcome to follow WeChat official account【程序猿编码
参考:https://redis.io/docs/

相关文章:

Linux下C/C++ redis协议(RESP)解析

Redis是一个开源的内存键值数据存储&#xff0c;最常用作主数据库、缓存、消息代理和队列。Redis提供了亚毫秒的响应时间&#xff0c;在游戏、金融科技、广告技术、社交媒体、医疗保健和物联网等行业实现了快速而强大的实时应用。 Redis连续五年成为开发人员最喜爱的数据库。开…...

IDEA 性能优化设置

在我们日常使用IDEA进行开发时&#xff0c;可能会遇到许多卡顿的瞬间&#xff0c;明明我们的机器配置也不低啊&#xff1f;为什么就会一直卡顿呢&#xff1f; “ 原来这是因为IDEA软件在我们安装的时候就设置了默认的内存使用上限&#xff08;通常很小&#xff09;&#xff0c;…...

蓝桥杯刷题冲刺 | 倒计时4天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;倒计时4天&#xff0c;冲冲冲&#xff01;&#xff01;&#xff01;&#x1f43e; 文章目录1.整除序列2.走方格3.前缀和4.差分矩阵5.翻硬币1.整除序列 题目 链接&#xff1a; 2065. 整除序列 - Ac…...

阿里测试7年经验,从功能测试到自动化测试,我整理的超全学习指南

做测试七年多&#xff0c;有不少人问过我下面问题&#xff1a; 现在的手工测试真的不行了吗&#xff1f;测试工程师&#xff0c;三年多快四年的经验&#xff0c;入门自动化测试需要多久&#xff1f;自学自动化测试到底需要学哪些东西&#xff1f;不得不说&#xff0c;随着行业的…...

jar加密后当作SDK给别人使用(可maven引入)

1、不加密jar&#xff0c;进行提取公共代码&#xff0c;打成jar包&#xff0c;并用maven引入 参考文章&#xff1a;以maven添加依赖的方式导入自己写的项目。springboot 提取公共类&#xff0c;多服务共用 2、加密jar&#xff0c;使用ClassFinal进行jar的加密 官网地址:Clas…...

【编程基础】032、C语言中结构体在解题中的应用

文章目录C语言中结构体在解题中的应用1、结构体之时间设计2、结构体之成绩记录3、结构体之成绩统计2C语言中结构体在解题中的应用 1、结构体之时间设计 题目描述 定义一个结构体变量&#xff08;包括年、月、日&#xff09;。计算该日在本年中是第几天&#xff0c;注意闰年问…...

Kotlin 是后端开发的未来

Kotlin 是后端开发的未来 严格类型、命名参数、多范式语言 您今天遇到的每个后端开发人员都会说他们使用 JavaScript、Python、PHP 或 Ruby 编写代码。近年来&#xff0c;您会遇到一小部分人转而使用 Kotlin 作为他们创建 Web 服务器的语言选择。由于我在学习Ktor&#xff0c;所…...

Vue3学习笔记(9.1)

Vue.js style&#xff08;内联样式&#xff09; 我们可以在v-bind:style直接设置样式&#xff0c;可以简写:style <!--* Author: RealRoad1083425287qq.com* Date: 2023-04-02 19:41:53* LastEditors: Mei* LastEditTime: 2023-04-03 15:41:44* FilePath: \vscode\Vue3_li…...

MinIO 环境变量泄漏漏洞(CVE-2023-28432)

漏洞描述 MinIO 是一个开源的对象存储服务器。 MinIO RELEASE.2023-03-20T20-16-18Z之前版本中的 bootstrap-peer-server.go#VerifyHandler 方法存在敏感信息泄漏漏洞&#xff0c;攻击者可向集群部署中的 MinIO 服务器的 /minio/bootstrap/v1/verify API发送POST请求&#xf…...

数组转字符串、字符串转数组的方法

一.数组转字符串方法 方法转化后类型用法特点toString()string将数组转换成了一个字符串默认用","隔开toLocaleString()string把数组转换成本地约定的字符串默认用","隔开join()string将数组元素连接起来以构建一个字符串 默认用","隔开 可以随…...

local fault和remote fault

1、什么是 local fault和remote fault? 在IEEE802.3协议中&#xff0c;local fault和remote fault是一种错误序列&#xff0c;在PCS层定义。 MAC RX侧收到local fault时&#xff0c;意味本地链路没有正常建立链路&#xff0c;MAC RX侧收到remote fault时&#xff0c;意味对端没…...

二叉树搜索树 AVL树

文章目录1. 二叉搜索树1.1 二叉搜索树概念1.2 二叉搜索树操作1.3 二叉搜索树的实现1.4 二叉搜索树的应用1.5 二叉搜索树的性能分析2. AVL 树2.1 AVL树的概念2.2 AVL树节点的定义2.3 AVL树的插入2.4 AVL树的旋转2.5 AVL树的验证2.7 AVL树的性能3. 具体代码实现区3.1 二叉搜索树的…...

nginx配置代理多个前端资源

log: 背景 两套不同的前端使用同一个后端服务&#xff0c;前端使用的Nginx代理的dist包 前端 vueelementui 后端 Pythonflask Nginx代理设置 1.进入Linux机器&#xff0c;whereis nginx 查看Nginx安装位置 2.进到Nginx配置文件下 3.vim nginx.conf 通过多个server管理…...

SuperMap iServer下载安装,启用服务,以及发布服务

supermap 是一套专注于 GIS 产品开发的全过程解决方案&#xff0c;主要包括桌面 GIS 、云 GIS 和 Web SDK&#xff0c;这里主要介绍如何使用它的云服务器 iServer 进行三维地图及数据服务的发布&#xff0c;iServer 里面还可进行负载均衡、集群等高级配置&#xff0c;有兴趣的可…...

vxe-table简单使用 vue vxe-table vue整合vxe-table vue2 vxe-table 简单使用

vxe-table简单使用 vue vxe-table vue整合vxe-table vue2 vxe-table 简单使用安装vxe-table引用使用安装vxe-table vue2稳定版本 vue3稳定版本 npm install xe-utils vxe-tablelegacy安装 vxe-table 依赖的插件 npm i xe-utils引用 我这边是全局引入&#xff0c;可以根据自…...

Vue项目的打包上线步骤

Vue项目的打包上线步骤一、打包之前的路由模式二、性能分析和CDN的应用2.1 性能分析2.2 webpack排除打包2.3 CDN文件配置2.4 注入CDN文件到模板一、打包之前的路由模式 两种路由模式 hash模式 &#xff1a; #后面是路由路径&#xff0c;特点是前端访问&#xff0c;#后面的变化不…...

都2023了,学习自动化测试还有必要么?会不会浪费我时间

最近收到不少小伙伴私信提问&#xff0c;其中问得比较多的就是“学习自动化测试有那么重要吗&#xff1f;”。 我的回答是肯定的——很重要。 相信不少同学都有诸如此类的疑问&#xff0c;例如&#xff1a;“日常工作中好像用不上自动化&#xff1f;”、“手工点点点好像也可…...

银行数字化转型导师坚鹏:如何有效推进银行数字化转型工作

如何有效推进银行数字化转型工作 ——以推动银行数字化转型战略落地为核心&#xff0c;实现知行果合一课程背景&#xff1a; 很多银行都在开展银行数字化转型工作&#xff0c;目前存在以下问题急需解决&#xff1a;不清楚有效推进银行数字化转型的关键性工作&#xff1f;不…...

【MySQL高级篇】第09章_性能分析工具的使用

第09章_性能分析工具的使用 在数据库调优中&#xff0c;我们的目标是 响应时间更快, 吞吐量更大 。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式。 1. 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该如何思考呢&#xff1…...

关于xhtml和html的区别

HTML是一种基本的WEB网页设计语言&#xff0c;XHTML是一个基于XML的置标语言&#xff0c;看起来与HTML有些相象&#xff0c;只有一些小的但重要的区别。本文简单介绍什么是XHTML&#xff0c;以及与HTML相比XHTML有什么特点。   1、什么是XHTML&#xff1f;   HTML是一种基本…...

原生JavaScript比较两个日期大小,项目中通用

原生JavaScript比较两个日期大小&#xff0c;项目中通用&#xff0c;具体日期比较大小一、比较两个日期大小&#xff08;月份&#xff09;1.开始时间大于结束时间2.开始时间等于结束时间3.开始时间大于结束时间二、比较两个日期大小&#xff08;日期&#xff09;代码如下&#…...

【JAVA真的没出路了吗?】

2023年了&#xff0c;转行IT学习Java是不是已经听过看过很多次了。随之而来的类似学Java没出路、Java不行了、对Java感到绝望等等一系列的制造焦虑的话题也在网上层出不穷&#xff0c;席卷了一大片的对行业不了解的吃瓜群众或是正在学习中的人。如果是行外人真的会被这种言论轻…...

PCB模块化设计11——VGA高速PCB布局布线设计规范

目录PCB模块化设计11——VGA高速PCB布局布线设计规范1、什么是VGA&#xff1f;2、VGA接口管脚定义3、VGA电缆究竟是如何工作的&#xff1f;4、VGA参考设计原理图5、PCB设计指南1、R,G,B LAYOUT注意事项2、HSYNC,VSYNC Layout注意事项3、其他注意事项PCB模块化设计11——VGA高速…...

【Python】【进阶篇】五、Python爬虫的抓取网页

目录五、Python爬虫的抓取网页5.1 导入所需模块5.2 获取目标URL地址5.3 向目标URL发送请求5.4 保存为本地文件5.5 优化程序五、Python爬虫的抓取网页 Python 爬虫应用案例&#xff1a;爬取目标的网页&#xff0c;并将其保存到本地。 对要编写的爬虫程序进行分析&#xff0c;可…...

docker安装MongoBD(超详细)

一、安装docker 推荐文章&#xff1a;https://blog.csdn.net/Sumuxi9797926/article/details/127313307?spm1001.2014.3001.5502 二、创建主机挂载配置目录 data目录存放mongodb数据库文件&#xff0c;删除重启容器不会丢失 mkdir -p /docker/mongodb/data && cd …...

6轴陀螺仪姿态解算

之前看过学长姿态解算相关代码&#xff0c;因为要做平衡车的项目&#xff0c;希望陀螺仪处理数据能够达到很好的效果&#xff0c;大概2个星期前&#xff0c;看的学长代码&#xff0c;当时把大部分代码看懂是用来干什么的&#xff0c;但原理还是一窍不通&#xff0c;没办法&…...

提升集群吞吐量与稳定性的秘诀: Dubbo 自适应负载均衡与限流策略实现解析

作者&#xff1a;刘泉禄 整体介绍 本文所说的“柔性服务”主要是指 consumer 端的负载均衡和 provider 端的限流两个功能。在之前的 Dubbo 版本中&#xff0c;负载均衡部分更多的考虑的是公平性原则&#xff0c;即 consumer 端尽可能平等的从 provider 中作出选择&#xff0c;…...

大数据分析工具Power BI(十七):制作过程分析和原因分析图表

制作过程分析和原因分析图表 一、过程分析 过程分析主要分析业务流程中每一步骤的变化情况,用于分析业务流程指标数据变化、拆分业务流程、拆分关键业务指标等等。可以使用漏斗图、瀑布图来展示过程分析数据。 1、漏斗图 漏斗图常用来展示业务过程的线性变化,分析业务流程的转…...

公司“007”式工作的卷王测试员,被辞退了…

上周&#xff0c;公司传出同事小王被开除的消息&#xff0c;震惊了一办公室的人。要知道&#xff0c;小王在办公室素有卷王之称&#xff0c;不仅从没见他6点准点下班过&#xff0c;早上也都第一个到。平时的周报&#xff0c;也都洋洋洒洒的写了5K字之多&#xff0c;他的存在一度…...

C++ Primer第五版_第七章习题答案(1~10)

文章目录练习7.1练习7.2练习7.3练习7.4练习7.5练习7.6练习7.7练习7.8练习7.9练习7.10练习7.1 使用2.6.1节定义的Sales_data类为1.6节的交易处理程序编写一个新版本。 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; us…...