最清晰的逻辑教你使用多进程实现TCP套接字词典查询(多并发/cs架构/MySQL/完整代码)
在线字典查询项目设计文档
文章目录
- 在线字典查询项目设计文档
- 功能要求
- 基本要求
- 用户可以登录和注册
- 可以通过基本的图形界面print以提示客户端输入
- 界面要求
- 客户端启动后即进入一级界面,包含如下功能:登录 注册 退出
- 用户登录后进入二级界面,功能如下:查单词 历史记录 注销
- 需求分析
- 多并发方案—多进程
- 网络传输方法—TCP
- 技术细节
- 数据库设计
- 模块设计
- 整体概述
- 客户端模块- client
- 服务端模块- server
- 数据库操作模块- db_operate
- 完整代码
- 客户端(client.py)
- 服务器(server.py)
- 数据库操作(dboperate.py)
功能要求
基本要求
用户可以登录和注册
登录凭借用户名和密码登录
注册要求用户必须填写用户名,密码,其他内容自定
用户名要求不能重复
要求用户信息能够长期保存
可以通过基本的图形界面print以提示客户端输入
程序分为服务端和客户端两部分
客户端通过print打印简单界面输入命令发起请求
服务端主要负责逻辑数据处理
启动服务端后应该能满足多个客户端同时操作
界面要求
客户端启动后即进入一级界面,包含如下功能:登录 注册 退出
退出后即退出该软件
登录成功即进入二级界面,失败回到一级界面
注册成功可以回到一级界面继续登录,也可以直接用注册用户进入二级界面
用户登录后进入二级界面,功能如下:查单词 历史记录 注销
选择注销则回到一级界面
查单词:循环输入单词,得到单词解释,输入特殊符号退出单词查询状态
历史记录:查询当前用户的查词记录,要求记录包含name word time。可以查看所有记录或者前10条均可。
需求分析
多并发方案—多进程
应对多个用户登录情况,可行方案主要有多进程、多线程、多路IO复用,均可选择,本例使用多进程Process实现
方案 | 实现方法 |
---|---|
多进程 |
os模块fork()实现多进程: multiprocessing模块Process实现多进程: 1.为单独的入口函数开辟单独进程 2.自定义进程类,run定义启动函数,可以将共同使用的数据封装为类实例变量 |
多线程 |
multiprocessing模块Tread实现多进程: 1.与Process进程模块使用方法相同 2.注意区别python线程和进程的区别 |
IO多路复用 |
IO多路复用适合处理IO请求密集型问题,对于长期占用服务处理逻辑需要用多进程/线程 select–rs,ws,xs=select(rlist,wlist,xlist) rlist监听读属性IO,连接结束删除监听对象 poll—fdmap存放文件描述符与IO对象字典,register添加监听对象 epoll-- 与poll使用方法相同,但内部实现机制不同,epoll效率最高,可设置边缘触发 |
网络传输方法—TCP
使用TCP网络通信方式,特点是无丢失,无失序,无差错,无重复
技术细节
细节 | 实现 |
---|---|
注册信息 | 用户名,密码 |
历史记录 | 用户名,查询单词,查询时间----数据库查询最近10条记录:时间排序 |
密码 |
暗文输入:getpass模块getpass([prompt]) 存储加密:hashlib模块中的MD5加盐加密 |
# MD5加密算法调用
hash=hashlib.md5("salt**@来干小日本!".encode()) # 参数为加盐内容,可缺省
password="123456"
hash.update(password.encode())
secret=hash.hexdigest()
数据库设计
模块设计
整体概述
整体设计使用类实现封装。客户端模块实现用户交互interface,负责用户输入,结果呈现等基本功能;服务器模块采用多进程并发处理客户端连接请求;数据库模块处理数据读写,包括加码处理等;
客户端模块- client
class OnlineDictClient(): def __init__(self): # 客户端连接套接字初始化def mian(self): # 登录注册(一级界面)def regist(self): # 用户注册 def login(self): # 用户登录def dict(self,name): # 主要功能界面:查询,历史记录(二级界面) def search(self,name): # 查询 def history(self,name): # 历史记录查看
服务端模块- server
class OnlineDictServer():def __init__(self): # 数据库对象,监听套接字初始化def main(self): # 循环监听,分配子进程def handle(self,client): # 子进程处理主逻辑,解析客户端请求内容def regist(self, client,request): # 用户注册逻辑处理def login(self,client,info_log): # 用户登录逻辑处理def search(self,client,request): # 用户查询字典逻辑处理def history(self,client,request): # 用户查看历史记录逻辑处理
数据库操作模块- db_operate
import pymysql,hashlib
class DataBase():def __init__(self): # 初始化,连接数据库def secret(self,pwd): # 密码加密,hashlib模块MD5处理密码def register(self, name, pwd):# 用户注册,数据库写操作-->table user:name password def login(self,name,pwd): # 用户登录,数据库读操作<--select from user def search(self,name,word): # 用户查询,读单词解释<--select words:explain def inserthistory(self,name,word): # 用户查询记录写入,name,word和time-->historydef history(self,name): # 历史记录查看,返回最近10条记录<--select+order by+limit 10
完整代码
客户端(client.py)
from socket import *
import pymysql
from getpass import getpass
import sysclass OnlineDictClient():# 客户端连接套接字初始化def __init__(self):self.ADDR=("127.0.0.1",5200) #服务器地址self.socketclient=socket()self.socketclient.connect(self.ADDR)# 登录注册(一级界面)def mian(self):while True:print("""=======Online Dict=======1.注册 2.登录 3.退出=========================""")cmd=input("输入选项:")if cmd not in ("1","2","3"):print("请输入正确选项!")continue# 直接将选项作为请求格式,避免再次拟定发送格式if cmd=="1": # 注册self.regist()elif cmd=="2": # 登录self.login()elif cmd=="3": # 退出sys.exit("谢谢使用!")# 用户注册def regist(self):while True:name=input("请输入名称:")# pwd=input("请输入密码:")# pwdc=input("请再次确认密码:")pwd=getpass()pwdc=getpass("Again:")if pwd!=pwdc:print("输入密码不一致")continueif " " in name or " " in pwd:print("输入用户名或密码不合法,包含空格")continues="R %s %s"%(name,pwd)self.socketclient.send(s.encode())confirm=self.socketclient.recv(1024)if confirm==b"OK":print("注册成功")breakelse:print("注册失败,用户名已存在!")# 用户登录def login(self):while True:print("""=======Online Dict=======用户登录界面=========================""")name = input("请输入您的名称:")pwd = input("请输入您的密码:")s="L %s %s"%(name,pwd)self.socketclient.send(s.encode())info_cfrm=self.socketclient.recv(1024)if info_cfrm==b"OK":print("恭喜登陆成功!")self.dict(name)breakelse:print("用户名或密码错误,请重新输入!")# 主要功能界面:查询,历史记录(二级界面)def dict(self,name):while True:print("""=======Online Dict=======1.英语单词查询2.历史记录查看3.注销=========================""")cmd=input("请输入选项:")if cmd == "1": # 查询self.search(name)elif cmd == "2": # 历史记录self.history(name)elif cmd == "3": # 退出return# 查询def search(self,name):self.socketclient.send(("S %s"%name).encode())while True:word =input("请输入查询单词:")if not word:self.socketclient.send(b"EXIT")breakself.socketclient.send(word.encode())explain=self.socketclient.recv(1024)if explain==b"404":print("无此单词")else:print(explain.decode())# 历史记录查看def history(self,name):self.socketclient.send(("H %s"%name).encode())history=self.socketclient.recv(2048)print("您的历史记录:\n",history.decode())
if __name__=="__main__":client=OnlineDictClient()client.mian()
服务器(server.py)
from socket import *
import pymysql
from multiprocessing import *
from signal import *
from db_operate import *
import sys
class OnlineDictServer():# 数据库对象,监听套接字初始化def __init__(self):# 数据库对象调用self.db=DataBase()# 套接字初始化self.port=5200self.ip="127.0.0.1"self.ADDR=(self.ip,self.port) #服务器地址self.socketfd=socket()self.socketfd.bind(self.ADDR)self.socketfd.listen(5)print("Listen from port:%d"%self.port)self.socketfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)signal(SIGCHLD,SIG_IGN)# 循环监听,分配子进程def main(self):print("")while True:try:conn,addr=self.socketfd.accept()print("connect from",addr)except Exception:print("服务器退出!")self.p=Handle(conn,self.db)self.p.start()
class Handle(Process):def __init__(self,conn,db):self.conn=connself.db=dbsuper().__init__()# 子进程处理主逻辑,解析客户端请求内容def run(self):while True:request=self.conn.recv(1024).decode()if not request or request[0]=="E":sys.exit(0)elif request[0] == "R":self.regist(request)elif request[0] == "L":self.login(request)elif request[0]=="S":self.search(request)elif request[0] == "H":self.history(request)# 用户注册逻辑处理def regist(self, request):name=request.split(" ")[1]pwd=request.split(" ")[-1]if self.db.register(name,pwd):self.conn.send(b"OK")else:self.conn.send(b"name exist")# 用户登录逻辑处理def login(self,info_log):name = info_log.split(" ")[1]pwd = info_log.split(" ")[-1]if self.db.login(name,pwd):self.conn.send(b"OK")else:self.conn.send(b"incorrect")# 用户查询字典逻辑处理def search(self,request):name=request.split(" ")[-1]while True:word=self.conn.recv(1024).decode()if word=="EXIT":breakexplain=self.db.search(name,word)if explain:self.conn.send(explain.encode())else:self.conn.send(b"404")# 用户查看历史记录逻辑处理def history(self,request):name=request.split(" ")[-1]records=self.db.history(name)if records:self.conn.send(records.encode())else:self.conn.send(("%s have no search history"%name).encode())
if __name__=="__main__":server=OnlineDictServer()server.main()
数据库操作(dboperate.py)
import pymysql
import hashlib
class DataBase():# 初始化,连接数据库def __init__(self):self.db=pymysql.connect(host="localhost",port=3306,user="root",password="123456",database="dict",charset='utf8' )# 游标self.cur = self.db.cursor()# 密码加密,hashlib模块MD5处理密码def secret(self,pwd):hash=hashlib.md5("salt**来干小日本!".encode())hash.update(pwd.encode())return hash.hexdigest()# 用户注册,数据库写操作-->table user:name passworddef register(self, name, pwd):# 对密码进行加密处理pwd=self.secret(pwd)# 判断是否存在该用户名sql = "select name from user where name='%s';" % nameself.cur.execute(sql)if self.cur.fetchone():return False# 插入记录try:sql = "insert into user (name,password) values ('%s','%s')" % (name, pwd)self.cur.execute(sql)# 写操作self.db.commit()return Trueexcept:self.db.rollback()return False# 用户登录,数据库读操作<--select from userdef login(self,name,pwd):pwd = self.secret(pwd)sql="select * from user where name='%s' and password='%s'"%(name,pwd)self.cur.execute(sql)if self.cur.fetchone():return Trueelse:return False# 用户查询,插入查询name,word和time-->historydef inserthistory(self,name,word):sql="insert into history (name,word) values ('%s','%s')"%(name,word)try:self.cur.execute(sql)self.db.commit()except:self.db.rollback()# 用户查询,记录,读单词解释<--select words:explaindef search(self,name,word):self.inserthistory(name,word)sql = "select wordexplain from words where word='%s'" % wordself.cur.execute(sql)# 返回结果为元组explain=self.cur.fetchone()if explain:return explain[0]# 历史记录查看,返回最近10条记录def history(self,name):sql = "select * from history where name=%s order by searchtime desc limit 10"self.cur.execute(sql,[name])records=self.cur.fetchall()str_=""for record in records:str_+=(str(record)+"\n")return str_
if __name__=="__main__":db=DataBase()res=db.history("lei")print(res)
最清晰的逻辑教你使用多进程实现TCP套接字词典查询(多并发/cs架构/MySQL/完整代码)相关推荐
- Linux下套接字详解(五)----基于fork多进程的TCP套接字(阻塞/同步/并发)
简介 一个简单的改进方案是在服务器端使用多线程(或多进程).多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接.具体使用多进程还是多线程,并没有 ...
- 套接字编程---2(TCP套接字编程的流程,TCP套接字编程中的接口函数,TCP套接字的实现,TCP套接字出现的问题,TCP套接字多进程版本,TCP套接字多线程版本)
TCP模型创建流程图 TCP套接字编程中的接口 socket 函数 #include <sys/types.h> /* See NOTES */ #include <sys/sock ...
- 教你使用 SO_REUSEPORT 套接字选项提升服务性能
前言 Linux 网络栈中有一个相对较新的特性--SO_REUSEPORT 套接字选项,可以使用它来提升你的服务性能. 图 1: 上面的服务是使用并行监听器来避免请求连接瓶颈,而下面的服务只使用一个监 ...
- Maven项目+MVC三层架构+Mysql+Tomcat+私教预约系统前后端(私教、用户、管理员)+可以用于学习SSM框架、javaweb、maven项目入门
Maven项目+MVC三层架构+Mysql+Tomcat+私教预约系统前后端(私教.用户.管理员)+可以用于学习SSM框架.javaweb.maven项目入门 可以用于课程设计.毕业设计的知识点入门学 ...
- 《卡尔威特的教育》读书摘抄及相关感想2400字
<卡尔威特的教育>读书摘抄及相关感想2400字: 世界上的绝大部分工作须先培训才能上岗,而"为人父母"这份工作似乎是人类本能使然,大多数父母没做过入职前的培训就懵懵懂 ...
- 计算机网络套接字编程实验-TCP多进程并发服务器程序与单进程客户端程序(简单回声)
1.实验系列 ·Linux NAP-Linux网络应用编程系列 2.实验目的 ·理解多进程(Multiprocess)相关基本概念,理解父子进程之间的关系与差异,熟练掌握基于fork()的多进程编程模 ...
- Linux_套接字(C++_TCP回显服务器——多进程/线程池(生产者消费者模型)处理多链接请求)
文章目录 1.多进程版本 服务端 启动服务端 客户端 启动客户端 本地测试 2.多线程版本 3.模板线程池版本 线程池代码: 设计任务Task.h 服务端代码 1.多进程版本 这里选择创建子进程,让子 ...
- 好玩的deep dream(清晰版,pytorch完整代码)
本文给出pytorch完整代码实现deep dream,加入了图像金字塔处理和高斯平滑处理,使生成图更加清晰美观.文中还讨论了各种因素对生成图的影响. 1, 完整代码 Deep dream图是 ...
- 计算机考试遇到不会读的字,不会读的字怎么打 轻松几招教你怎样打不会读的字...
之前有一篇"你会写火字吗"一文在网络中爆红,讲述的是随着我们队计算机依赖性不断增强,很多人已经开始忘记字怎么写了,就连一个最简单的"火"字都忘记了,引来众多网友 ...
- 【机器学习入门】(9) 逻辑回归算法:原理、精确率、召回率、实例应用(癌症病例预测)附python完整代码和数据集
各位同学好,今天我和大家分享一下python机器学习中的逻辑回归算法.内容主要有: (1) 算法原理:(2) 精确率和召回率:(3) 实例应用--癌症病例预测. 文末有数据集和python完整代码 1 ...
最新文章
- Spring Data ElasticSearch示例--使用NativeSearchQuery查询
- boost::icl模块实现测试 shell 来分割区间图
- SpringMVC自定义拦截器与异常处理(自定义异常)
- Windows、Linux和MAC的CR, LF, CR/LF换行符
- 首次使用mysql_mysql-8.0.20-winx64_初次使用过程(Win7x64)
- gitlab和jenkins发布代码
- [tensorflow]tensorflow2.1.0使用内置方法进行培训和评估
- 从门户到搜索:谁为百度打工?
- Java流处理之转换编码的转换流
- 【经验分享】BMPR文件及其打开软件Balsamiq Wireframes的下载和安装
- 骑士旅行问题(骑士走棋盘)
- hibernate Criteria setProjection
- Android:adb卸载系统应用软技能
- Discuz!论坛运营之如何开启发帖回帖@会员功能
- Python3:numpy的简单使用4(矩阵间的操作,合并数组,分割数组,读取文件操作)
- 一道关于索引的使用和key_len的计算的面试题
- JAVA实现AES加密
- 女生宿舍-同名专辑《女生宿舍 Life Is Beautiful》
- 39-Figma-APP套样机方法
- slqite3库查询数据处理方式_C语言实现sqlite3数据库查询的基本方法
热门文章
- Java经典编程习题100例:第18例:编写程序,将一个数组中的元素倒排过来。例如原数组为1,2,3,4,5;则倒排后数组中的值
- 救救企鹅(字符串hash)
- 【C# 教程系列第 23 篇】什么是Json?
- SEMer必会:通过SEO思维为网站获取精准流量
- ceph 数据均衡调整
- java timer任务
- SAP FICO 会计科目/客户/供应商/公司代码(组)OB55创建工作清单满足报表查询需求
- 新插的内存条BIOS无法认到!
- 辽宁省劳动经济学校计算机专业,辽宁省劳动经济学校计算机与艺术系专业介绍...
- 学术圈都在关注的公众号有哪些?我们帮你一次性get