使用Python开发SQLite代理服务器的方法


Posted in Python onDecember 07, 2018

SQLite数据库使用单个磁盘文件,并且不需要像Oracle、MSSQL、MySQL等数据库管理系统那样启动服务,使用非常灵活方便。但是SQLite也有个很严重的问题,就是没有相应的服务,也没有监听任何端口,因此相应的程序只能访问本地数据库。也就是说,无法分离程序和数据库,只能把程序和数据库放在同一台计算机上。

本文使用Python开发了一个SQLite数据库的服务程序,可以完美地分离程序和数据库。技术要点是Socket编程,在数据库服务器上运行服务程序,该服务程序监听特定端口、执行代理程序发来的SQL语句并返回结果;代理程序负责接收客户端的SQL语句并转发给服务器,然后再把服务器返回的结果转发给客户端。在具体使用时可以在本文代码基础上进行简化和扩展。

服务程序:

##
# 服务器程序,接收代理服务器转发来的SQL指令,并返回结果
#
import sqlite3
import socket
import struct

def getData(sql):
 '''通过给定的SQL SELECT语句返回结果'''
 with sqlite3.connect(r'database.db') as conn:
  cur = conn.cursor()
  cur.execute(sql)
  result = cur.fetchall()
 return result

def doSql(sql):
 '''适用于DELETE/UPDATE/INSERT INTO语句,返回影响的记录条数'''
 with sqlite3.connect(r'database.db') as conn:
  cur = conn.cursor()
  result = cur.execute(sql)
 return result.rowcount

# 创建socket对象,默认使用IPV4+TCP
sockServer = socket.socket()
sockServer.bind(('', 3030))
sockServer.listen(1)
while True:
 # 接收客户端连接
 try:
  conn, addr = sockServer.accept()
 except:
  continue
 
 sql = conn.recv(1024).decode('gbk').lower()
 
 if sql.startswith(('update','delete','insert')):
  try:
   # 首先发送要发送的字节总数量
   # 然后再发送真实数据
   result = str(doSql(sql)).encode('gbk')
   conn.send(struct.pack('i', len(result)))
   conn.send(result)
  except:
   message = b'error'
   conn.send(struct.pack('i', len(message)))
   conn.send(message)
 elif sql.startswith('select'):
  try:
   result = str(getData(sql)).encode('gbk')
   conn.send(struct.pack('i', len(result)))
   conn.send(result)
  except:
   message = b'error'
   conn.send(struct.pack('i', len(message)))
   conn.send(message)

代理程序:

##
# 代理服务器,在SQLite数据库服务器和客户端之间进行指令和数据的转发
# 这样可以把数据库和程序放到两个服务器上进行分离
##
import socket
from threading import Thread
import struct

sockServer = socket.socket()
sockServer.bind(('',5050))
sockServer.listen(50)

def agent(conn):
 # 接收客户端发来的指令,并进行过滤
 sql = conn.recv(1024)
 if not sql.decode('gbk').startswith(('select', 'delete', 'insert','update')):
  message = b'not a sql statement'
  conn.send(struct.pack('i', len(message)))
  conn.send(message)
  return
 else:
  sockClient = socket.socket()
  # 尝试连接服务器
  try:
   sockClient.connect(('10.2.1.3', 3030))
  except:
   message = b'Server not alive'
   conn.send(struct.pack('i', len(message)))
   conn.send(message)
   return
   
  # 向服务程序转发SQL语句
  sockClient.send(sql)
  # 数据量大小,使用sturct序列化一个整数需要4个字节
  size = sockClient.recv(4)
  conn.send(size)
  size = struct.unpack('i', size)[0]
  while True:
   if size == 0:
    break
   elif size > 4096:
    data = sockClient.recv(4096)
    conn.send(data)
    size -= len(data)
   else:
    data = sockClient.recv(size)
    conn.send(data)
    size -= len(data)
  sockClient.close()
 conn.close()

while True:
 conn, _ = sockServer.accept()
 Thread(target=agent, args=(conn,)).start()

模拟客户端程序:

##
# 模拟客户端,向SQLite代理服务器发送指令并接收数据
#
import sqlite3
import socket
import struct

while True:
 sql = input('输入一个要执行的SQL语句:\n')
 # 没有输入,进入下一次循环
 if sql.strip() == '':
  continue
 
 # 输入exit或quit,退出客户端
 if sql in ('exit', 'quit'):
  break
 # 建立socket,尝试连接
 sockClient = socket.socket()
 try:
  sockClient.connect(('10.2.1.3', 5050))  
 except:
  print('服务器异常,请检查')
 else:
  # 发送远程SQL语句
  sockClient.send(sql.encode('gbk'))
  size = sockClient.recv(4)
  size = struct.unpack('i', size)[0]
  
  data = b''
  while True:
   if size == 0:
    break
   elif size > 4096:
    # 注意断包和粘包
    # 虽然设置了4096,但是不一定能够接收4096字节
    #即使缓冲区的数据远多于4096
    t = sockClient.recv(4096)
    data += t
    size -= len(t)
   else:
    t = sockClient.recv(size)
    data += t
    size -= len(t)
  data = data.decode('gbk')
  try:
   data = eval(data)
  except:
   pass
  sockClient.close()
  print(data)

以上这篇使用Python开发SQLite代理服务器的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python学习笔记(一)(基础入门之环境搭建)
Jun 05 Python
python调用百度语音识别api
Aug 30 Python
python使用xlrd模块读取xlsx文件中的ip方法
Jan 11 Python
Python3实现的回文数判断及罗马数字转整数算法示例
Mar 27 Python
简单了解python协程的相关知识
Aug 31 Python
Numpy之reshape()使用详解
Dec 26 Python
pytorch 实现cross entropy损失函数计算方式
Jan 02 Python
Python打印特殊符号及对应编码解析
May 07 Python
tensorflow图像裁剪进行数据增强操作
Jun 30 Python
Python字符串及文本模式方法详解
Sep 10 Python
python import 上级目录的导入
Nov 03 Python
基于 Python 实践感知器分类算法
Jan 07 Python
解决python 未发现数据源名称并且未指定默认驱动程序的问题
Dec 07 #Python
Python中collections模块的基本使用教程
Dec 07 #Python
对python 操作solr索引数据的实例详解
Dec 07 #Python
python用post访问restful服务接口的方法
Dec 07 #Python
python3 实现验证码图片切割的方法
Dec 07 #Python
python 用opencv调用训练好的模型进行识别的方法
Dec 07 #Python
Python cv2 图像自适应灰度直方图均衡化处理方法
Dec 07 #Python
You might like
法压式咖啡之制作法
2021/03/03 冲泡冲煮
php下通过POST还是GET来传值
2008/06/05 PHP
ThinkPHP CURD方法之field方法详解
2014/06/18 PHP
php输入流php://input使用浅析
2014/09/02 PHP
改善用户体验的五款jQuery插件分享
2011/05/22 Javascript
关于onScroll事件在IE6下每次滚动触发三次bug说明
2011/09/21 Javascript
JQuery1.8 判断元素是否绑定事件的方法
2014/07/10 Javascript
仿百度联盟对联广告实现代码
2014/08/30 Javascript
JQuery 使用attr方法实现下拉列表选中
2014/10/13 Javascript
Jquery对象和Dom对象的区别分析
2014/11/20 Javascript
JS实现5秒钟自动封锁div层的方法
2015/02/20 Javascript
js使用split函数按照多个字符对字符串进行分割的方法
2015/03/20 Javascript
jquery插件splitScren实现页面分屏切换模板特效
2015/06/16 Javascript
深入理解 JavaScript 中的 JSON
2017/04/06 Javascript
收藏AngularJS中最重要的核心功能
2017/07/09 Javascript
老生常谈js中的MVC
2017/07/25 Javascript
jquery+css3实现熊猫tv导航代码分享
2018/02/12 jQuery
vue裁切预览组件功能的实现步骤
2018/05/04 Javascript
webpack4 处理CSS的方法示例
2018/09/03 Javascript
Python字典及字典基本操作方法详解
2018/01/30 Python
Pycharm 操作Django Model的简单运用方法
2018/05/23 Python
哪些是python中web开发框架
2020/06/17 Python
python在一个范围内取随机数的简单实例
2020/08/16 Python
使用phonegap获取位置信息的实现方法
2017/03/31 HTML / CSS
Canvas在超级玛丽游戏中的应用详解
2021/02/06 HTML / CSS
2014年教师培训的自我评价
2014/01/03 职场文书
客户服务经理岗位职责
2014/01/29 职场文书
中考冲刺决心书
2014/03/11 职场文书
3.12植树节活动总结2014
2014/03/13 职场文书
小学安全工作汇报材料
2014/08/19 职场文书
办公室领导干部作风整顿个人整改措施
2014/09/17 职场文书
办公室文员工作自我鉴定
2014/09/19 职场文书
2015年元宵节活动总结
2015/02/06 职场文书
乒乓球比赛通知
2015/04/27 职场文书
使用golang编写一个并发工作队列
2021/05/08 Golang
MySQL创建管理RANGE分区
2022/04/13 MySQL