• 数据库:socketserver模块、MySQL(一)


    一、socketserver实现并发

    基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环。

    socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)

    server类:

    request类:

    继承关系:

     

    以下述代码为例,分析socketserver源码:

    ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
    ftpserver.serve_forever()

    查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer

    1. 实例化得到ftpserver,先找类ThreadingTCPServer的__init__,在TCPServer中找到,进而执行server_bind,server_active
    2. 找ftpserver下的serve_forever,在BaseServer中找到,进而执行self._handle_request_noblock(),该方法同样是在BaseServer中
    3. 执行self._handle_request_noblock()进而执行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然后执行self.process_request(request, client_address)
    4. 在ThreadingMixIn中找到process_request,开启多线程应对并发,进而执行process_request_thread,执行self.finish_request(request, client_address)
    5. 上述四部分完成了链接循环,本部分开始进入处理通讯部分,在BaseServer中找到finish_request,触发我们自己定义的类的实例化,去找__init__方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler中找....

    源码分析总结:

    基于tcp的socketserver我们自己定义的类中的

    1. self.server即套接字对象
    2. self.request即一个链接
    3. self.client_address即客户端地址

    基于udp的socketserver我们自己定义的类中的

    1. self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
    2. self.client_address即客户端地址
    import os
    import time
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    import socket
    import selectors
    
    class selectFtpServer:
    
        def __init__(self):
            self.dic = {}
            self.hasReceived=0
            self.sel = selectors.DefaultSelector()
            self.create_socket()
            self.handle()
    
        def create_socket(self):
            server = socket.socket()
            server.bind(("127.0.0.1",8885))
            server.listen(5)
            server.setblocking(False)
            self.sel.register(server, selectors.EVENT_READ, self.accept)
            print("服务端已开启,等待用户连接...")
    
        def handle(self):
            while True:
                events = self.sel.select()
                for key, mask in events:
                    callback = key.data
                    callback(key.fileobj, mask)
    
        def accept(self,sock, mask):
    
            conn, addr = sock.accept()
            print("from %s %s connected"%addr)
            conn.setblocking(False)
            self.sel.register(conn, selectors.EVENT_READ, self.read)
    
            self.dic[conn] = {}
    
        def read(self, conn, mask):
            try:
                if not self.dic[conn] :
    
                    data = conn.recv(1024)
                    cmd,filename,filesize = str(data, encoding='utf-8').split('|')
                    self.dic={conn:{"cmd": cmd, "filename": filename,"filesize": int(filesize)}}
    
                    if cmd == 'put':
                        conn.send(bytes("OK",encoding='utf8'))
    
                    if self.dic[conn]['cmd'] == 'get':
                        file = os.path.join(BASE_DIR,"download",filename)
    
                        if os.path.exists(file):
                            fileSize = os.path.getsize(file)
                            send_info = '%s|%s'%('YES',fileSize)
                            conn.send(bytes(send_info, encoding='utf8'))
                        else:
                            send_info = '%s|%s'%('NO',0)
                            conn.send(bytes(send_info, encoding='utf8'))
                else:
                    if self.dic[conn].get('cmd',None):
                        cmd=self.dic[conn].get('cmd')
                        if hasattr(self, cmd):
                            func = getattr(self,cmd)
                            func(conn)
                        else:
                            print("error cmd!")
                            conn.close()
                    else:
                        print("error cmd!")
                        conn.close()
    
            except Exception as e:
                print('error', e)
                self.sel.unregister(conn)
                conn.close()
    
        def put(self, conn):
    
            fileName = self.dic[conn]['filename']
            fileSize = self.dic[conn]['filesize']
            path = os.path.join(BASE_DIR,"upload",fileName)
            recv_data = conn.recv(1024)
            self.hasReceived += len(recv_data)
    
            with open(path, 'ab') as f:
                f.write(recv_data)
            if fileSize == self.hasReceived:
                if conn in self.dic.keys():
                    self.dic[conn] = {}
                print("%s上传完毕!"%fileName)
    
        def get(self,conn):
    
            filename = self.dic[conn]['filename']
            path = os.path.join(BASE_DIR,"download",filename)
            if str(conn.recv(1024), 'utf-8') == "second_active":
                with open(path, 'rb') as f:
                    for line in f:
                        conn.send(line)
                self.dic[conn] = {}
                print('文件下载完毕!')
    
    
    if __name__ == '__main__':
    
        selectFtpServer()
    FtpServer
    import socket
    import os,sys
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    
    class selectFtpClient:
    
        def __init__(self):
            self.args=sys.argv
            if len(self.args)>1:
                self.port=(self.args[1],int(self.args[2]))
            else:
                self.port=("127.0.0.1",8885)
            self.create_socket()
            self.command_fanout()
    
        def create_socket(self):
            try:
                self.sk = socket.socket()
                self.sk.connect(self.port)
                print('连接FTP服务器成功!')
            except Exception as e:
                print("error: ",e)
    
        def command_fanout(self):
            while True:
                cmd = input('>>>').strip()
                if cmd == 'exit()':
                    break
                cmd,file = cmd.split()
                if hasattr(self, cmd):
                    func = getattr(self, cmd)
                    func(cmd,file)
                else:
                    print('调用错误!')
    
        def put(self,cmd,file):
    
            if os.path.isfile(file):
                fileName= os.path.basename(file)
                fileSize = os.path.getsize(file)
                fileInfo ='%s|%s|%s'%(cmd,fileName,fileSize)
                self.sk.send(bytes(fileInfo, encoding='utf8'))
                recvStatus = self.sk.recv(1024)
                print('recvStatus', recvStatus)
                hasSend = 0
                if str(recvStatus, encoding='utf8') == "OK":
                    with open(file, 'rb') as f:
                        while fileSize > hasSend :
                            contant = f.read(1024)
                            recv_size = len(contant)
                            self.sk.send(contant)
                            hasSend += recv_size
                            s=str(int(hasSend/fileSize*100))+"%"
                            print("正在上传文件:"+fileName+"   已经上传:"+s)
                    print('%s文件上传完毕' % (fileName,))
            else:
                print('文件不存在')
    
        def get(self, cmd,file):
           pass
    if __name__ == '__main__':
    
        selectFtpClient()
    FtpClient

    二、数据库简介

    1、数据库

    数据库(database,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合。数据库中的数据按一定的数学模型组织、描述和存储,具有较小的冗余,较高的数据独立性和易扩展性,并可为各种用户共享。

    2、数据库管理系统软件

    数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户通过DBMS访问数据库中的数据,数据库管理员也通过dbms进行数据库的维护工作。它可使多个应用程序和用户用不同的方法在同时或不同时刻去建立,修改和询问数据库。大部分DBMS提供数据定义语言DDL(Data Definition Language)和数据操作语言DML(Data Manipulation Language),供用户定义数据库的模式结构与权限约束,实现对数据的追加、删除等操作。

    数据库管理系统是数据库系统的核心,是管理数据库的软件。数据库管理系统就是实现把用户意义下抽象的逻辑数据处理,转换成为计算机中具体的物理数据处理的软件。有了数据库管理系统,用户就可以在抽象意义下处理数据,而不必顾及这些数据在计算机中的布局和物理位置。

    常见的数据库管理软件:甲骨文的oracle,IBM的db2,sql server, Access,Mysql(开源,免费,跨平台).

    3、数据库系统

    数据库系统DBS(Data Base System,简称DBS)通常由软件、数据库和数据管理员组成。其软件主要包括操作系统、各种宿主语言、实用程序以及数据库管理系统。数据库由数据库管理系统统一管理,数据的插入、修改和检索均要通过数据库管理系统进行。数据管理员负责创建、监控和维护整个数据库,使数据能被任何有权使用的人有效使用。

     

    三、MySQL

    1、mysql的管理

    安装

    linux:

    --yum -y install mariadb mariadb-server
    OR
    --yum -y install mysql mysql-server

    win:

    --http://dev.mysql.com/downloads/mysql/ 

    启动

    --service mysqld start  #开启
    --chkconfig mysqld on   #设置开机自启
    OR
    --systemctl start mariadb
    --systemctl enable mariadb

    查看

    -- ps aux |grep mysqld    #查看进程
    -- netstat -an |grep 3306 #查看端口

    设置密码

    -- mysqladmin -uroot password '123'   #设置初始密码,初始密码为空因此-p选项没有用
    -- mysqladmin -u root -p123 password '1234' #修改root用户密码

    登录

    -- mysql               #本地登录,默认用户root,空密码,用户为root@127.0.0.1
    -- mysql -uroot -p1234 #本地登录,指定用户名和密码,用户为root@127.0.0.1
    -- mysql -uroot -p1234 -h 192.168.31.95 #远程登录,用户为root@192.168.31.95

    mysql的常用命令

    -- 
    -- 启动mysql服务与停止mysql服务命令:
    -- 
    -- net start mysql
    -- net stop  mysql
    -- 
    -- 
    -- 登陆与退出命令:
    -- 
    --    mysql -h 服务器IP -P 端口号 -u  用户名 -p 密码 --prompt 命令提示符  --delimiter 指定分隔符
    --    mysql -h 127.0.0.1 -P 3306 -uroot -p123
    --    quit------exit----q;
    -- 
    -- 
    -- s;   ------my.ini文件:[mysql] default-character-set=gbk [mysqld] character-set-server=gbk
    -- 
    -- prompt 命令提示符(D:当前日期 d:当前数据库  u:当前用户)
    -- 
    -- T(开始日志) 	(结束日志)
    -- 
    -- show warnings;
    -- 
    -- help() ? h
    -- 
    -- G;
    -- 
    -- select now();
    -- select version();
    -- select user;
    -- 
    -- c 取消命令
    -- 
    -- delimiter 指定分隔符

    忘记密码怎么办?

    方法1:启动mysql时,跳过授权表

    [root@controller ~]# service mysqld stop
    [root@controller ~]# mysqld_safe --skip-grant-table &
    [root@controller ~]# mysql
    mysql> select user,host,password from mysql.user;
    +----------+-----------------------+-------------------------------------------+
    | user     | host                  | password                                  |
    +----------+-----------------------+-------------------------------------------+
    | root     | localhost             | *A4B6157319038724E3560894F7F932C8886EBFCF |
    | root     | localhost.localdomain |                                           |
    | root     | 127.0.0.1             |                                           |
    | root     | ::1                   |                                           |
    |          | localhost             |                                           |
    |          | localhost.localdomain |                                           |
    | root     | %                     | *23AE809DDACAF96AF0FD78ED04B6A265E05AA257 |
    +----------+-----------------------+-------------------------------------------+
    mysql> update mysql.user set password=password("123") where user="root" and host="localhost";
    mysql> flush privileges;
    mysql> exit
    [root@controller ~]# service mysqld restart
    [root@controller ~]# mysql -uroot -p123

    方法2(删库):

    删除与权限相关的库mysql,所有的授权信息都丢失,主要用于测试数据库或者刚刚建库不久没有授权数据的情况(从删库到跑路)
    [root@controller ~]# rm -rf /var/lib/mysql/mysql
    [root@controller ~]# service mysqld restart
    [root@controller ~]# mysql

    2、sql语句

    sql是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而建立的操作命令集,是一种功能齐全的数据库语言。

    在使用它时,只需要发出“做什么”的命令,“怎么做”是不用使用者考虑的。SQL功能强大、简单易学、使用方便,已经成为了数据库操作的基础,并且现在几乎所有的数据库均支持sql。

    2.1sql规范

    <1> 在数据库系统中,SQL语句不区分大小写(建议用大写) 。但字符串常量区分大小写。建议命令大写,表名库名小写;

    <2> SQL语句可单行或多行书写,以“;”结尾。关键词不能跨多行或简写。

    <3> 用空格和缩进来提高语句的可读性。子句通常位于独立行,便于编辑,提高可读性。

    SELECT * FROM tb_table
                WHERE NAME="YUAN";

    <4> 注释:单行注释:--

                   多行注释:/*......*/

    <5>sql语句可以折行操作

    <6> DDL,DML和DCL

    -- --SQL中 DML、DDL、DCL区别 .
    
    -- -- DML(data manipulation language):
    --    它们是SELECT、UPDATE、INSERT、DELETE,就象它的名字一样,这4条命令是用来对数据库里的
    --    数据进行操作的语言
    -- 
    -- -- DDL(data definition language):
    --    DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)
    --    的结构,数据类型,表之间的链接和约束等初始化工作上,他们大多在建立表时使用
    -- 
    -- -- DCL(Data Control Language):
    --    是数据库控制功能。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)
    --    语句。在默认状态下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人员才有权
    --    力执行DCL
    View Code

    2.2关于数据库操作的sql语句

    -- 1.创建数据库(在磁盘上创建一个对应的文件夹)
        create database [if not exists] db_name [character set xxx] 
        
    -- 2.查看数据库
        show databases;查看所有数据库
        show create database db_name; 查看数据库的创建方式
    
    -- 3.修改数据库
        alter database db_name [character set xxx] 
    
    -- 4.删除数据库
        drop database [if exists] db_name;
        
    -- 5.使用数据库
        切换数据库 use db_name; -- 注意:进入到某个数据库后没办法再退回之前状态,但可以通过use进行切换
        查看当前使用的数据库 select database();

    2.3数据表的增删改查

    创建一张表

    -- 语法
    create table tab_name(
                field1 type[完整性约束条件],
                field2 type,
                ...
                fieldn type
            )[character set xxx];
    -- 创建一个员工表employee
    
             create table employee(
                id int primary key auto_increment ,
                name varchar(20),
                gender bit default 1,   -- gender char(1)  default 1   -----    或者 TINYINT(1) 
                birthday date,       
                job varchar(20),
                salary double(4,2) unsigned,
                resume text    -- 注意,这里作为最后一个字段不加逗号
              );
    
     /* 约束:
           primary key (非空且唯一)  :能够唯一区分出当前记录的字段称为主键!
           unique         
           not null
           auto_increment :用于主键字段,主键字段必须是数字类型
      */

    查看表信息

    desc tab_name 查看表结构
        show columns from tab_name  查看表结构
        show tables 查看当前数据库中的所有的表
        show create table tab_name    查看当前数据库表建表语句 

    修改表结构

    -- (1)增加列(字段)
          alter table tab_name add [column] 列名 类型[完整性约束条件][first|after 字段名];
          alter table user add addr varchar(20) not null unique first/after username;
          #添加多个字段
          alter table users2 
                add addr varchar(20),
                add age  int first,
                add birth varchar(20) after name;
    
       -- (2)修改一列类型
          alter table tab_name modify 列名 类型 [完整性约束条件][first|after 字段名];
          alter table users2 modify age tinyint default 20;
          alter table users2 modify age int  after id;
       
       -- (3)修改列名
          alter table tab_name change [column] 列名 新列名 类型 [完整性约束条件][first|after 字段名];
          alter table users2 change age Age int default 28 first;
    
       -- (4)删除一列
          alter table tab_name drop [column] 列名;
          -- 思考:删除多列呢?删一个填一个呢?
          alter table users2 
                add salary float(6,2) unsigned not null after name,
                drop addr;    
    
       -- (5)修改表名
          rename table 表名 to 新表名;
    
       -- (6)修该表所用的字符集    
          alter table student character set utf8;

    删除表

    drop table tab_name;
  • 相关阅读:
    python web 2
    python web1(解析url)
    webstrom 今天突然要激活
    数组排序 记录一下
    浏览器添加随机数去除缓存
    vue-cli 安装报错
    vue 初始化项目报错
    深拷贝和浅拷贝
    css3 属性 clip-path
    js数组去重
  • 原文地址:https://www.cnblogs.com/Vee-Wang/p/7231705.html
Copyright © 2020-2023  润新知