redispython源文件_python redis-py 源码分析

一 概述

通常python 连接redis数据库用的redis-py 这个三方库,最近研究了一下它的源码

·

使用方式:

import redis

# 下面两步只是实例化创建了连接池,并未进行实际连接

conn_pool = redis.ConnectionPool(host='1.2.2.2', port=63, password='xxx', db=0)

conn = redis.StrictRedis(connection_pool=conn_pool)

# 第一次执行命令时才会去连接

conn.ping()

下面我们一步一步去了解

执行ping命令时 在client.py 模块,会执行 StrictRedis 类的方法 self.execute_command

# COMMAND EXECUTION AND PROTOCOL PARSING

def execute_command(self, *args, **options):

"Execute a command and return a parsed response"

pool = self.connection_pool

command_name = args[0]

# 从连接池获取连接

connection = pool.get_connection(command_name, **options)

try:

# 这里开始去连接redis服务

connection.send_command(*args)

# 返回解析的结果

return self.parse_response(connection, command_name, **options)

except (ConnectionError, TimeoutError) as e:

connection.disconnect()

if not connection.retry_on_timeout and isinstance(e, TimeoutError):

raise

connection.send_command(*args)

return self.parse_response(connection, command_name, **options)

finally:

pool.release(connection)

send_command 会调下面的方法

def send_packed_command(self, command):

"Send an already packed command to the Redis server"

if not self._sock:

# 开始连接

self.connect()

try:

if isinstance(command, str):

command = [command]

for item in command:

self._sock.sendall(item)

except socket.timeout:

self.disconnect()

raise TimeoutError("Timeout writing to socket")

except socket.error:

e = sys.exc_info()[1]

self.disconnect()

if len(e.args) == 1:

errno, errmsg = 'UNKNOWN', e.args[0]

else:

errno = e.args[0]

errmsg = e.args[1]

raise ConnectionError("Error %s while writing to socket. %s." %

(errno, errmsg))

except:

self.disconnect()

raise

它连接服务器的函数是这个 _connect 函数

def _connect(self****):

"""创建一个tcp socket 连接"""

# we want to mimic wha****t socket.create_connection does to support

# ipv4/ipv6, but we want to set options prior to calling

# socket.connect()

err = None

for res in socket.getaddrinfo(self.host, self.port, 0,

socket.SOCK_STREAM):

family, socktype, proto, canonname, socket_address = res

sock = None

try:

sock = socket.socket(family, socktype, proto)

# TCP_NODELAY

sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

# TCP 长连接

if self.socket_keepalive:

sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

for k, v in iteritems(self.socket_keepalive_options):

sock.setsockopt(socket.SOL_TCP, k, v)

# 我们连接之前设置socket_connect_timeout超时时间

sock.settimeout(self.socket_connect_timeout)

# 连接

sock.connect(socket_address)

# 连接成功后设置 socket_timeout 时间

sock.settimeout(self.socket_timeout)

return sock

except socket.error as _:

err = _

if sock is not None:

sock.close()

if err is not None:

raise err

raise socket.error("socket.getaddrinfo returned an empty list")

on_connect 函数,实列化连接,有密码则发送密码,选择数据表

def on_connect(self):

"Initialize the connection, authenticate and select a database"

self._parser.on_connect(self)

# if a password is specified, authenticate

if self.password:

# 如果redis服务做了进一步的安全加固,也是在这里进行鉴权

self.send_command('AUTH', self.password)

if nativestr(self.read_response()) != 'OK':

raise AuthenticationError('Invalid Password')

# if a database is specified, switch to it

if self.db:

self.send_command('SELECT', self.db)

if nativestr(self.read_response()) != 'OK':

raise ConnectionError('Invalid Database')

它的连接池使用一个list来做的

def reset(self):

self.pid = os.getpid()

# 创建的连接数

self._created_connections = 0

# 存放可用的连接

self._available_connections = []

# 存放已经再用的连接

self._in_use_connections = set()

# 线程锁

self._check_lock = threading.Lock()

获取连接

def get_connection(self, command_name, *keys, **options):

"Get a connection from the pool"

self._checkpid()

try:

# 从list获取连接

connection = self._available_connections.pop()

except IndexError:

# 不存在测创建连接

connection = self.make_connection()

# 并添加到可用连接集合

self._in_use_connections.add(connection)

return connection

创建新的连接

def make_connection(self):

"Create a new connection"

if self._created_connections >= self.max_connections:

raise ConnectionError("Too many connections")

self._created_connections += 1

return self.connection_class(**self.connection_kwargs)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值