• PYTHON2.day10


    前情回顾

    1. 多线程并发网络模型
    2. 基于Process的多进程并发网络
    3. 集成模块socketserver完成网络并发
    4. HTTPServer v2.0:模块封装,多线程并发,请求解析
    5. 协程基础 : 定义,原理,优缺点
    6. 介绍greenlet,学习gevent
          【1】 gevent.spawn()  生成协程对象
          【2】 gevent.joinall()  阻塞等待协程执行完成
          【3】 gevent.sleep()  提供gevent阻塞

    *********************************************************
    一. gevent模块(续)

      1. 动机:在gevent协程中,协程只有遇到gevent指定类型的阻塞才能跳转到其他协程,因此,我们希望将普通的IO阻塞行为转换为可以触发gevent协程跳转的阻塞,以提高执行效率。

        2. 转换方法:gevent 提供了一个脚本程序monkey,可以修改底层解释IO阻塞的行为,将很多普通阻塞转换为gevent阻塞。
      
            【1】 导入monkey
                    from gevent  import monkey

             【2】 运行相应的脚本,例如转换socket中所有阻塞
                          monkey.patch_socket()
                
              【3】 如果将所有可转换的IO阻塞全部转换则运行all
                    monkey.patch_all()
                
              【4】 注意:脚本运行函数需要在对应模块导入前执行

      1 import gevent
      2 from gevent import monkey
      3 monkey.patch_all()#执行脚本插件,修改IO阻塞行为
      4 from socket import *
      5 
      6 #创建套接字
      7 def server():
      8     s = socket()
      9     s.bind(('0.0.0.0',8888))
     10     s.listen(10)
     11     while True:
     12         c,addr = s.accept()#主程序遇到阻塞触发协程
     13         print("Conect from",addr)#打印客户端
     14         # handle(c)#处理客户端请求
     15         gevent.spawn(handle,c)#把函数变成协程,c->不定参数}-----协程方案,多客户端
     16 
     17 def handle(c):
     18     while True:
     19         data = c.recv(1024)#协程阻塞在recv
     20         if not data:
     21             break
     22         print(data.decode())
     23         c.send(b"OK")
     24 
     25 server()
     26 
    gevent_server.py
      1 from socket import *
      2 
      3 #创套接字
      4 sockfd = socket()
      5 
      6 #发起连接
      7 server_addr = ('172.40.71.149',8888)
      8 sockfd.connect(server_addr)
      9 
     10 #收发消息
     11 while  True:
     12     data = input(">>")
     13     if not data:
     14         break
     15     sockfd.send(data.encode())
     16     data = sockfd.recv(1024)
     17     print("From server:",data.decode())
     18 
     19 #关闭套接子
     20 sockfd.close()
     21 
    tcp_clent.py

    gevent_server


    二. 网络电子词典

      1. 功能说明
          【1】用户可以登录和注册
                 * 登录凭借用户名和密码登录
                     * 注册要求用户必须填写用户名,密码,其他内容自定
                     * 用户名要求不能重复
                     * 要求用户信息能够长期保存
            
            【2】可以通过基本的图形界面print以提示客户端输入。
                 * 程序分为服务端和客户端两部分
                     * 客户端通过print打印简单界面输入命令发起请求
                     * 服务端主要负责逻辑数据处理
                     * 启动服务端后应该能满足多个客户端同时操作
            
             【3】客户端启动后即进入一级界面,包含如下功能:
                 
                      登录    注册    退出

                     * 退出后即退出该软件
                      * 登录成功即进入二级界面,失败回到一级界面
                      * 注册成功可以回到一级界面继续登录,也可以直接用注册用户进入二级界面
            
             【4】用户登录后进入二级界面,功能如下:
                 
                      查单词    历史记录    注销

                     * 选择注销则回到一级界面
                      * 查单词:循环输入单词,得到单词解释,输入特殊符号退出单词查询状态
                      * 历史记录:查询当前用户的查词记录,要求记录包含name   word   time。可以查看所有记录或者前10条均可。
        
         2. 单词本说明

          【1】 特点 : 1. 每个单词一定占一行
                          2. 单词按照从小到大顺序排列
                                      3. 单词和解释之间一定有空格
            
             【2】 查词说明 : 1. 直接使用单词本查询(文本操作)
                                                 2. 先将单词存入数据库,然后通过数据库查询。(数据库操作)
            
       3. 操作步骤
           
             【1】 确定并发方案? 确定套接字使用? 确定具体细节?
               使用文件查询还是数据库?
                        
                         * fork 多进程 ,tcp套接字
                         * 注册后回到一级界面,历史记录显示最近10条
                         * 文本直接查询

       
             【2】 建立数据库 : 建立几个表,表关系,表字段及类型
                   * 想办法将单词导入数据库
                        
                         用户表 : id   name   passwd
                         历史记录:id   name   word    time
                         单词存储:id   word   mean

                        1. 创建数据库:
                           create database dict default charset=utf8;

                        2. 创建用户表:
                             create table user (id int primary key auto_increment,name varchar(32) not null,passwd varchar(16) default '000000');
              
                         3. 创建历史记录表:
                             create table hist (id int primary key auto_increment,name varchar(32) not null,word varchar(32) not null,time varchar(64));
                        
                         4. 创建单词表:
                             create table words (id int primary key auto_increment,word varchar(32),mean text);


             【3】 结构设计:即如何封装,客户端和服务端工作流程。具体项目有几个功能模块。

                        * 函数封装
                         * 客户端启动--》进入一级界面--》登录--》二级界面--》具体请求--》展示内容
                         * 服务端循环接收请求--》处理请求--》将数据发送给客户端
                         * 功能模块:登录,注册,查询单词,历史记录


             【4】 完成通信的搭建

            【5】 分析具体通能,逐个模块实现
                
              
                     1、注册
              客户端:*输入注册信息
                                              *将信息发送给服务端
                          *得到服务器反馈
              服务端:*接收请求
                          *判断是否允许注册
                          *反馈结果给客户端
                          *如果可以注册则插入数据库
           
                     2. 登录
                             客户端: * 输入用户名密码
                                              * 将信息发送给服务器
                                              * 得到服务端反馈
                                              * 如果登录成功进入二级界面
                            
                             服务端: * 接收请求
                                              * 判断是否允许登录
                                              * 反馈结果

                    3. 查词
                         客户端 : * 输入查询单词
                                                 * 发送请求给服务端
                                                 * 获取结果
                            
                             服务端 : * 接收请求
                                                 * 查找单词
                                                 * 将查询结果发送给客户端
                                                 * 插入历史记录

                    4. 历史记录

      1 import pymysql
      2 
      3 f = open('dict.txt')
      4 db = pymysql.connect('localhost','root','123456','dict')
      5 
      6 cursor = db.cursor() #创建游标
      7 
      8 for line in f:
      9     tmp = line.split(' ')
     10     world = tmp[0]
     11     mean = ' '.join(tmp[1:]).strip()
     12     sql='insert into worlds (world,mean) values ("%s","%s")'%(world,mean)
     13 
     14     try:
     15         cursor.execute(sql)
     16         db.commit()
     17     except Exception:
     18         db.rollback()
     19 f.close()
    worlds_dict.py
      1 '''
      2 dict project for AID
      3 '''
      4 from socket import *
      5 import pymysql
      6 import os,sys
      7 import time#处理沾包
      8 import signal#处理僵尸
      9 
     10 #定义全局变量
     11 if len(sys.argv)<3:
     12     print('''Start as:
     13         python3 dict_server.py 0.0.0.0 8000
     14         ''')
     15     sys.exit(0)
     16 
     17 HOST = sys.argv[1]
     18 PORT = int(sys.argv[2])
     19 ADDR = (HOST,PORT)
     20 DICT_TEXT = "./dict.txt"
     21 
     22 #搭建网络连接
     23 def main():
     24     #连接数据库
     25     db = pymysql.connect('localhost','root','123456','dict')
     26     #创建套接字
     27     s = socket()
     28     # s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
     29     s.bind(ADDR)
     30     s.listen(5)
     31 
     32 
     33     #僵尸进程处理
     34     signal.signal(signal.SIGCHLD,signal.SIG_IGN)
     35 
     36 
     37     while True:
     38         try:
     39             c,addr = s.accept()
     40             print("Connect from",addr)
     41         except KeyboardInterrupt:
     42             s.close()
     43             sys.exit("服务器退出")
     44         except Exception as e:
     45             print(e)
     46             continue
     47 
     48         #创建子进程
     49         pid = os.fork()
     50         if pid ==0:
     51             s.close()
     52             do_child(c,db)
     53             sys.exit()
     54         else:
     55             c.close()
     56 
     57 
     58 
     59 
     60 
     61 #处理客户端请求
     62 def do_child(c,db):
     63     while True:
     64         #接收客户端请求
     65         data = c.recv(1024).decode()
     66         print(c.getpeername(),':',data)
     67         if not data or data[0]=="E":
     68             c.close()
     69             sys.exit()
     70         elif data[0]=='R':
     71             do_register(c,db,data)
     72         elif data[0]=='L':
     73             do_login(c,db,data)
     74         elif data[0]=='Q':
     75             do_query(c,db,data)
     76         elif data[0]=='H':
     77             do_hist(c,db,data)
     78 
     79 
     80 
     81 
     82 
     83 
     84 def do_register(c,db,data):
     85     l = data.split(' ')
     86     name =l[1]
     87     passwd = l[2]
     88     cursor = db.cursor()
     89 
     90     sql ="select * from user where name='%s'"%name
     91     cursor.execute(sql)
     92     r = cursor.fetchone()
     93     if r != None:
     94         c.send(b'EXITS')
     95         return
     96 
     97     #插入用户
     98     sql = "insert into user(name,passwd) values('%s','%s')"%(name,passwd)
     99     try:
    100         cursor.execute(sql)
    101         db.commit()
    102         c.send(b'OK')
    103     except:
    104         db.rollback()
    105         c.send(b'FAIL')
    106 
    107 
    108 
    109 def do_login(c,db,data):
    110     l = data.split(' ')
    111     name = l[1]
    112     passwd = l[2]
    113     cursor = db.cursor()
    114 
    115 
    116     sql = "select * from user where name='%s' and passwd='%s'"%(name,passwd)
    117     #查询用户
    118     cursor.execute(sql)
    119     r = cursor.fetchone()
    120     if r ==None:
    121         c.send(b'FAIL')
    122     else:
    123         c.send(b'OK')
    124 
    125 
    126 
    127 
    128 
    129 def do_query(c,db,data):
    130     l = data.split(' ')
    131     name = l[1]
    132     world = l[2]
    133 
    134 
    135     #插入历史记录
    136     cursor = db.cursor()
    137     tm = time.ctime()
    138     sql = "insert into hist(name,world,time) values ('%s','%s','%s')"%(name,world,tm)
    139     try:
    140         cursor.execute(sql)
    141         db.commit()
    142     except:
    143         db.rollback()
    144 
    145     #单词本查找
    146     f = open(DICT_TEXT)
    147 
    148     for line in f:
    149         tmp = line.split(' ')[0]#获取单词
    150         if tmp > world:
    151             break
    152         elif tmp == world:
    153             c.send(line.encode())
    154             return
    155     c.send("没有找到该单词")
    156     f.close()
    157 
    158 
    159 def do_hist(c,db,data):
    160     name = data.split(' ')[1]
    161     cursor = db.cursor()
    162     sql = "select * from hist where name='%s' order by id desc limit 10"%name
    163     cursor.execute(sql)
    164     r = cursor.fetchall()
    165     if not r:
    166         c.send(b'FAIL')
    167         return
    168     else:
    169         c.send(b'OK')
    170         time.sleep(0.1)
    171     for i in r:
    172         msg = "%s  %s  %s"%(i[1],i[2],i[3])
    173         c.send(msg.encode())
    174         time.sleep(0.1)
    175     c.send(b'##')
    176 
    177 
    178 
    179 
    180 if __name__=="__main__":
    181     main()
    182 
    dict_server.py
      1 from socket import *
      2 import sys
      3 import getpass
      4 
      5 #创建网络连接
      6 def main():
      7     if len(sys.argv) <3:
      8         print("argv is error")
      9         return
     10     HOST = sys.argv[1]
     11     PORT = int(sys.argv[2])
     12     s = socket()
     13     try:
     14         s.connect((HOST,PORT))
     15     except Exception as e:
     16         print(e)
     17         return
     18     while True:
     19         print('''
     20             ===============================wecome==============================
     21             --1.注册         2.登录        3.退出--
     22             ''')
     23         try:
     24             cmd = int(input("输入选项:"))
     25         except Exception as e:
     26             print("命令错误")
     27             continue
     28         if cmd not in [1,2,3]:
     29             print("请输入正确选项")
     30             continue
     31         elif cmd ==1:
     32             do_register(s)
     33         elif cmd ==2:
     34             do_login(s)
     35         elif cmd ==3:
     36             s.send(b'E')
     37             sys.exit("谢谢使用")
     38 
     39 def do_register(s):
     40     while True:
     41         name = input("User:")
     42         passwd = getpass.getpass()
     43         passwd1= getpass.getpass("Again:")
     44 
     45         if (' 'in name) or (' ' in passwd):
     46             print("用户名密码不能有空格")
     47             continue
     48         if passwd != passwd1:
     49             print("两次密码不一致")
     50             continue
     51 
     52         msg = "R %s %s"%(name,passwd)
     53         #发送请求
     54         s.send(msg.encode())
     55         #等待回复
     56         data = s.recv(128).decode()
     57         if data =='OK':
     58             print("注册成功")
     59             # login(s,name)#注册成功进入二级界面
     60         elif data =='EXISTS':
     61             print("用户已存在")
     62         else:
     63             print("注册失败")
     64         return
     65 
     66 
     67 
     68 def do_login(s):
     69     name = input("User:")
     70     passwd = getpass.getpass()
     71     msg = "L %s %s"%(name,passwd)
     72     s.send(msg.encode())
     73     data = s.recv(128).decode()
     74     if data =="OK":
     75         print("登录成功")
     76         login(s,name)
     77     else:
     78         print("登录失败")
     79 
     80 def login(s,name):
     81     while True:
     82         print('''
     83             ===============================wecome==============================
     84             --1.查词         2.历史记录        3.注销--
     85             ''')
     86         try:
     87             cmd = int(input("输入选项:"))
     88         except Exception as e:
     89             print("命令错误")
     90             continue
     91         if cmd not in [1,2,3]:
     92             print("请输入正确选项")
     93             continue
     94         elif cmd ==1:
     95             do_query(s,name)
     96         elif cmd ==2:
     97             do_hist(s,name)
     98         elif cmd ==3:
     99             return #回到一级界面
    100 
    101 def do_query(s,name):
    102     while True:
    103         world = input("单词:")
    104         if world == '##':
    105             break
    106         msg ='Q %s %s'%(name,world)
    107         s.send(msg.encode())
    108         #可能是单词解释.也可能是找不到
    109         data = s.recv(2048).decode()
    110         print(data)
    111 
    112 def do_hist(s,name):
    113     msg = "H %s"%name
    114     s.send(msg.encode())
    115     data = s.recv(128).decode()
    116     if data =="OK":
    117         while True:
    118             data = s.recv(1024).decode()
    119             if data =="##":
    120                 break
    121             print(data)
    122     else:
    123         print("没有历史记录")
    124 
    125 
    126 
    127 
    128 
    129 
    130 
    131 
    132 if __name__=="__main__":
    133     main()
    dict_clent.py

    words
    cookie :
       1. 收集命令行参数为一个列表

           【1】 import sys
              【2】 sys.argv 可以将命令行输入参数收集为一个列表
              【3】 默认命令行以空格分隔每一项,如果一个整体中有空格则用引号注明一个整体
              【4】 收集的列表中所有项均为字符串


       2.使用getpass输入密码
       【1】import getpass
       【2】passwd=getpass.getpass(),其中getpass()函数用法与input相同,只是可以自动
         隐藏输入内容


    作业 : 1. 整理进程线程网络内容
                     2. 复习mysql的理论内容和基本操作

  • 相关阅读:
    Android之TabHost实现Tab切换
    银联支付SDK集成
    iOS 支付 [支付宝、银联、微信]
    MySQL数据库数据类型以及INT(M)的含义
    cherrypy
    使用PyMySQL操作mysql数据库
    面向新手的Web服务器搭建(一)——IIS的搭建
    SQLite3中自增主键相关知识总结,清零的方法、INTEGER PRIMARY KEY AUTOINCREMENT和rowid的使用
    FMDB-FMDatabaseQueue
    SQLite 数据类型
  • 原文地址:https://www.cnblogs.com/shengjia/p/10439690.html