python读数据库的通信协议是什么_用 Python 实现 redis 方轮子-第 0 篇-了解通信协议...

本文介绍了Redis通信协议RESP的详细内容,包括其五种数据结构和解析过程。通过阅读,你可以理解如何使用Python实现一个简单的Redis服务器,处理不同类型的请求,并通过状态机进行解析。
摘要由CSDN通过智能技术生成

初识 RESP

当我们想实现一个 redis server,首先要了解 redis 的通信协议。

redis 作者认为数据库系统的瓶颈一般不在于网络流量上,所以使用了一个简单的纯文本的通信协议,叫做 RESP(Redis Serialization Protocol)。

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

RESP 定义了五种类型的数据结构,每个最小单元之间用\r\n隔开。

简单字符串 以 + 字符开头,后跟字符串本体。

错误消息 以 - 字符开头,后跟错误消息本体。

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

复杂字符串(最多 512M 的) 以 $ 字符开头,后跟字符串长度;后面再跟字符串本体。

数组 以 * 字符开头,后跟数组的长度;后面再跟数组元素。

如简单字符串:

"+OK\r\n"

错误消息:

"-Error message\r\n"

整数:

":1000\r\n"

":0\r\n"

复杂字符串:

"$6\r\nfoobar\r\n"

"$0\r\n\r\n"

"$-1\r\n" // 长度为-1 的是 null

数组:

"*0\r\n"

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

"*3\r\n:1\r\n:2\r\n:3\r\n"

"*-1\r\n" // 长度为-1 的是 null。比如 blpop 超时时应该返回它,客户端就应该展示为 null。

数组可以是混合类型,如数组的数组,把他们每行分隔开展示如下:

*2\r\n

*3\r\n

:1\r\n

:2\r\n

:3\r\n

*2\r\n

+Foo\r\n

-Bar\r\n

状态机

RESP 非常简单,协议的定义十分有限。所以要实现一个 redis server,我们可以按行读取客户端的请求数据,同时按行解析它们。

我们可以按照客户端的行数据到达的不同状态画出一个状态机。

649514dcgy1fv3rihi2slj20ip0bhgma.jpg

从 S 状态(开始状态)开始,如果接受到的字符串时+或-或:,则是三种最简单的一行数据结构:简单字符串、错误消息、整数。那么进入 A 状态,接下来接收到任意值,就进入 END 状态,代表一条请求接收完毕。

如果接收到的是$符号,那么进入 B 状态。接下来接收到-1则为 null,接收结束;接收到的是 0 或正整数,则进入 C 状态,此时还会接收到任意一行数据,就进入 END 状态代表结束。

如果接收到*号,代表数组,这时情况稍微复杂一点。先进入 D 状态,此时接受到的是0和-1的话都不会有一个新行,请求结束;此时接收到一个自然数值 n 的话,则代表数组长度为 n,则进入 En 状态,重新开始一个 S 状态的状态机,直到该状态机到 END 状态,n 可以自减 1 ;当 n 为 0 时,直接成为 END 状态。

Python 实现

RESP 的状态机实现部分略长,限于文章篇幅已经放在 GitHub:

redis server 的实现直接使用 Python 自带的 TCPServer:

from socketserver import TCPServer, StreamRequestHandler

from resp import handle_line

class RedisHandler(StreamRequestHandler):

def handle(self):

state = None

while True:

data = self.rfile.readline().strip()

print(data)

state = handle_line(data, state)

if state.is_stoped:

break

self.wfile.write(b'+OK\r\n')

print('end')

if __name__ == '__main__':

host, port = 'localhost', 6379

with TCPServer((host, port), RedisHandler) as server:

server.serve_forever()

现在不管什么请求到达,server 都会响应+OK\r\n给客户端。我们的 server 端还会打印出请求的每行字符。

运行效果

直接敲入

当敲入redis-cli时,可以看到客户端发送了一个长度为 1 的数组过来,里面只有一个字符串为COMMAND:

649514dcgy1fv3rk58442j20l8088t8t.jpg

我们在redis-cli敲入命令get a,客户端将get和a作为长度为 2 的数组发送到 server。当然,我们的 server 现在还只能响应OK给客户端。

649514dcgy1fv3rke6iokj20fj064jre.jpg

这个系列可能还会继续更新下去……

欢迎 star

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值