python 实战之在线字典

该文章描述了一个C/S结构的应用,涉及多进程并发、TCP网络通信以及使用MySQL进行持久化存储。应用采用类MVC模块设计,包括登录、注册、查询单词及查看历史记录功能。数据库包含用户、单词和查询历史三个表。客户端和服务端通过自定义的通信协议交互,实现了登录、注册、查询和历史记录的请求与响应。
摘要由CSDN通过智能技术生成

 需求分析: C/S

技术分析:

        并发:多进程并发

        网络:tcp

        持久化存储:mysql数据库

模块划分:类 mvc

        登录  注册 查询单词 历史记录

数据库建设:

        dict 数据库

create database dict;

        user表 

create table user (
id int primary key auto_increment,
name varchar(32) unique,
password char(64)
);

        words表

create table words (
id int primary key auto_increment,
word varchar(32),
mean varchar(1024)
);

        check_history表

create table check_history (
id int primary key auto_increment,
user_id int,
words_id int,
time DATETIME DEFAULT now(),
foreign key(user_id) references user(id) 
on delete cascade on update cascade,
foreign key(words_id) references words(id)
);

通信协议与响应

                        客户端                  服务端

注册                    I                           成功 T   失败 F

登录                    U

查询                     C

历史                      H

搭建客户端

"""
dict 客户端: 与用户交互
"""
from socket import socket

ADDR = ("localhost", 8888)  # 连接服务器的地址以及使用的端口


class Handle:
    def __init__(self):
        self.sock = self.__create_sock()

    def __create_sock(self):
        """
        创建套接字
        :return:套接字
        """
        sock = socket()
        sock.connect(ADDR)
        return sock

    def sing_in(self, msg):
        """
        向服务器发送注册请求
        :param msg:  I user password
        :return: 注册成功 True 注册失败 False
        """
        self.sock.send(msg.encode())
        judge = self.sock.recv(128).decode()
        if judge == "T":
            return True
        else:
            return False

    def sing_up(self, msg):
        """
        像服务器发送登录请求
        :param msg: U user password
        :return: 服务器响应
        """
        self.sock.send(msg.encode())
        judge = self.sock.recv(1024).decode()
        return judge

    def quit(self):
        self.sock.send(b"E")

    def check_word(self, word, user):
        """
        发起查询单词的请求
        :param user:  用户名
        :param word: 查询的单词
        :return: 单词解释
        """
        msg = "C\t%s\t%s" % (user, word)
        self.sock.send(msg.encode())
        data = self.sock.recv(124).decode()
        if data == "T":
            return self.sock.recv(1024).decode()  # word mean
        else:
            return "F"

    def display_history(self, user):
        """
        向服务端发起查询记录请求
        :return: 有记录 T 无记录 F
        """
        msg = "H\t%s" % user
        self.sock.send(msg.encode())
        judge = self.sock.recv(124).decode()
        if judge == "T":
            hist_list = []
            while True:
                record = self.sock.recv(1024).decode()
                if record == "##":
                    break
                hist_list.append(record)
            print(hist_list)
            return hist_list
        else:
            return judge


class Menu:
    def __init__(self):
        self.handle = Handle()

    def menu_1(self):
        """
        一级界面菜单
        """
        while True:
            print("""
            +++++++++++++ WELLCOME ++++++++++
                1.登录    2.注册    3.退出
            +++++++++++++++++++++++++++++++++
            """)
            cmd = input("请输入选项:")
            if cmd == "1":
                user = input("请输入用户:")
                password = input("请输入密码:")
                msg = "U\t%s\t%s" % (user, password)
                judge = self.handle.sing_up(msg)
                if judge == "T":
                    print("登录成功!")
                    self.__menu_2(user)
                elif judge == "N" or judge == "F":
                    print("账号错误")
                elif judge == "M":
                    print("密码错误")
                else:
                    print("未知错误!")

            elif cmd == "2":
                user = input("请输入用户:")
                password = input("请输入密码:")
                msg = "I\t%s\t%s" % (user, password)
                if self.handle.sing_in(msg):
                    print("注册成功!")
                    self.__menu_2(user)
                else:
                    print("注册失败!用户可能已存在")

            elif cmd == "3":
                self.handle.quit()
                print("欢迎再次登录")
                break
            else:
                print("请输入正确的选项!")

    def __menu_2(self, user):
        """
        二级界面菜单
        :param user: 用户名
        :return: 没有返回值
        """
        while True:
            print("""
            ++++++++++++++++ WELLCOME ++++++++++++++
                1.查询单词    2.历史记录    3.注销
            ++++++++++++++++++++++++++++++++++++++++
            """)
            cmd = input("请输入选项:")
            if cmd == "1":
                print("输入## 退出查询单词")
                while True:
                    word = input("请输入单词:")
                    if word == "" or word == "##":
                        break
                    msg = self.handle.check_word(word, user)
                    if msg != "F":
                        print(msg)
                    else:
                        print("单词不存在")
            elif cmd == "2":
                msg = self.handle.display_history(user)
                if msg != "F":
                    for i in msg:
                        print(i)
                        print("######################")
                else:
                    print("暂无查询记录!")
            elif cmd == "3":
                break
            else:
                print("请输入正确选项!")

    def start(self):
        """
        客户端启动函数
        :return:
        """
        self.menu_1()


if __name__ == '__main__':
    menu = Menu()
    menu.start()

搭建服务端

"""
就收请求,逻辑处理,返回响应
"""
from socket import socket
from multiprocessing import Process
from dict_db import *
from time import sleep

HOST = "127.0.0.1"
PORT = 8888


class Handle(Process):
    def __init__(self, conn):
        super().__init__()
        self.conn = conn
        self.db = DataHandle()

    def run(self):
        while True:
            request = self.conn.recv(1024)
            data = request.decode().split("\t", 1)
            if data[0] == "E" or not data:
                break
            elif data[0] == "I":
                print("sing in")
                self.sing_in_user(*data[1].split("\t"))
            elif data[0] == "U":
                self.sing_up_user(*data[1].split("\t"))
            elif data[0] == "C":
                print("check word", *data[1].split("\t"))
                self.check_words(*data[1].split("\t"))
            elif data[0] == "H":
                self.display_history_words(data[1])

    def sing_in_user(self, *info):
        print("sing in user ", info)
        if self.db.user_in(*info):
            self.conn.send(b"T")
        else:
            self.conn.send(b"F")

    def sing_up_user(self, user, password):
        judge = self.db.is_user(user, password).encode()
        self.conn.send(judge)

    def check_words(self, user, word):
        mean = self.db.is_word(user, word)
        if mean:
            self.conn.send(b"T")
            sleep(0.001)
            self.conn.send(mean.encode())
        else:
            self.conn.send(b"F")

    def display_history_words(self, user):
        recode = self.db.dis_hos_wor(user)
        if recode != "F":
            print("history \n", recode)
            self.conn.send(b"T")
            sleep(0.005)
            for item in recode:
                msg = "单词:{} \n意思:{} \n时间:{}".format(item[0], item[1], item[2])
                sleep(0.05)
                self.conn.send(msg.encode())
            sleep(0.005)
            self.conn.send(b"##")
        else:
            self.conn.send(b"F")


class DictServer:
    def __init__(self):
        self.ADDR = (HOST, PORT)
        self.sock = self.__create_sock()

    def __create_sock(self):
        sock = socket()
        sock.bind(self.ADDR)
        sock.listen(6)
        return sock

    def main(self):
        print("Listen the port %d" % PORT)
        while True:
            conn, addr = self.sock.accept()
            print("Connect from ", addr)
            # 为客户端建立一个进程
            handel = Handle(conn)
            handel.run()


if __name__ == '__main__':
    dict_server = DictServer()
    dict_server.main()

数据处理

"""
根据逻辑处理,提供需要的数据
"""
import hashlib
import pymysql

# 密码加密
def password_change(password):
    h = hashlib.sha256()
    h.update(password.encode())
    return h.hexdigest()


class DataHandle:
    def __init__(self):
        self.INFO = {
            "host": "localhost",
            "port": 3306,
            "user": "root",
            "password": "ludabo",
            "database": "dict",
            "charset": "utf8"
        }
        self.db = pymysql.connect(**self.INFO)
        self.cur = self.db.cursor()

    def close_db_cur(self):
        self.db.close()
        self.cur.close()

    def user_in(self, user, password):
        """
        在数据库中查询注册的账号是否已存在
        :param password: 用户密码
        :param user:  用户名
        :return: 存在 False 不存在 True
        """
        pwd = password_change(password)
        try:
            sql = "insert into user (name,password) values (%s,%s);"
            self.cur.execute(sql, (user, pwd))
            self.db.commit()
            return True
        except Exception as e:
            print(e)
            self.db.rollback()
            return False

    def is_user(self, user, password):
        """
        判断用户是否存在
        :param user: 用户名
        :param password: 用户密码
        :return: N 账号错误 T 登录成功 M 密码错误
        """
        try:
            sql = "select password from user where name = %s"
            self.cur.execute(sql, (user,))
            judge = self.cur.fetchone()
            # print("is user", judge) ("password",)
            pwd = password_change(password)
            if not judge:
                return "N"
            elif judge[0] == pwd:
                return "T"
            else:
                return "M"
        except Exception as e:
            print(e)
            return "S"

    def is_word(self, user, word):
        """
        在数据库中查询单词写入历史并返回结果
        :param word: 查询的单词
        :param user: 用户名
        :return: 查询到返回mean,查不到 False
        """
        try:
            sql = "select mean from words where word = %s;"
            self.cur.execute(sql, (word,))
            mean = self.cur.fetchone()
            print(mean)
            if mean:
                user_id, word_id = self.__get_word_name_id(word, user)
                self.__word_add_history(user_id, word_id)
                return mean[0]
            return False
        except Exception as e:
            print("is_word Error ", e)
            self.db.rollback()

    def __get_word_name_id(self, word, name):
        """
        查询单词和用户的id
        :param word: 单词
        :param name: 用户名
        :return: 用户id, 单词id
        """
        print("word name", word, name)
        user_id = ""
        word_id = ""
        try:
            sql = "select id from user where name = %s;"
            self.cur.execute(sql, (name,))
            user_id = self.cur.fetchone()[0]
            sql = "select id from words where word = %s;"
            self.cur.execute(sql, (word,))
            word_id = self.cur.fetchone()[0]
            print("id ", user_id, word_id)
        except Exception as e:
            print("get_id Error ", e)
        return user_id, word_id

    def __word_add_history(self, user_id, word_id):
        """
        将查询单词添加到历史记录中
        :param user_id: 用户id
        :param word_id: 单词id
        :return: None
        """
        try:
            sql = "insert into check_history (user_id,words_id) values (%s,%s);"
            self.cur.execute(sql, (user_id, word_id))
            self.db.commit()
        except Exception as e:
            self.db.rollback()
            print("word_add_history Error ", e)

    def dis_hos_wor(self, user):
        """
        查询历史
        :return: 最近查询单词 10条记录
        """
        try:
            sql = "select word,mean,time from words,user,check_history " \
                  "where check_history.words_id = words.id " \
                  "and user.id = check_history.user_id and name=%s " \
                  "order by check_history.time desc limit 10;"
            self.cur.execute(sql, (user,))
            data = self.cur.fetchall()
            if len(data) > 0:
                return data
            else:
                return "F"
        except Exception as e:
            print(e)

值得慢慢理理,写一写,对于理解 tcp Process pymysql 有一定的帮助

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值