一、IO模型回顾
为了解决IO操作导致CPU闲置的问题
1.阻塞模型
执行recv或accept时,如果数据没到达,就阻塞当前程序,并让出CPU,让其去执行其他任务
2.非阻塞模型
1.将recv、accept、send 都设置成了非阻塞
2.非阻塞情况下,没有数据会立马抛出异常,我们可以捕捉异常,然后切换到其他任务
3.缺点:如果一直没有数据,程序将一直做无意义的循环,浪费CPU资源
4.优势:单线程内并发可以处理多个客户端
3.多路复用
使用select来帮助我们检测socket的状态
4.异步IO模型
整个过程都是异步,包括wait_data和copy_data两个步骤
5.信号驱动IO模型
二、epoll模型
1.select 的问题:
1.当进程被唤醒,但它不清楚到底哪个socket有数据,因此只能遍历一遍存放进程的队列
2.每一次select的执行,都需要将这些进程加入到等待队列中
3.为了防止重复添加等待队列,当某一次操作完成时,也必须从等待队列中删除进程,所以select最大限制被设置为了1024,如此看来select连多线程都比不上
4.于是推出了poll 和epoll,而poll只是简单对select进行了优化,但是还不够完美 ,epoll才是最后的解决方案
**5.注意:epoll仅能在linux中使用 **
2.epoll解决的问题
1.避免频繁的对等待队列进行操作
2.避免遍历所有socket
3.epoll相关函数
import select 导入select模块
epoll = select.epoll() 创建一个epoll对象
epoll.register(文件句柄,事件类型) 注册要监控的文件句柄和事件
事件类型:
select.EPOLLIN 可读事件
select.EPOLLOUT 可写事件
select.EPOLLERR 错误事件
select.EPOLLHUP 客户端断开事件
epoll.unregister(文件句柄) 销毁文件句柄
epoll.poll(timeout) 当文件句柄发生变化,则会以列表的形式主动报告给用户进程,timeout
为超时时间,默认为-1,即一直等待直到文件句柄发生变化,如果指定为1
那么epoll每1秒汇报一次当前文件句柄的变化情况,如果无变化则返回空
epoll.fileno() 返回epoll的控制文件描述符(Return the epoll control file descriptor)
epoll.modfiy(fineno,event) fineno为文件描述符 event为事件类型 作用是修改文件描述符所对应的事件
epoll.fromfd(fileno) 从1个指定的文件描述符创建1个epoll对象
epoll.close() 关闭epoll对象的控制文件描述符
4.举例
1.服务端
# coding:utf-8
import socket, select
server = socket.socket()
server.bind(("127.0.0.1", 1688))
server.listen(5)
msgs = []
fd_socket = {server.fileno(): server}
epoll = select.epoll()
# 注册服务器的 写就绪
epoll.register(server.fileno(), select.EPOLLIN)
while True:
for fd, event in epoll.poll():
sock = fd_socket[fd]
print(fd, event)
# 返回的是文件描述符 需要获取对应socket
if sock == server: # 如果是服务器 就接受请求
client, addr = server.accept()
# 注册客户端写就绪
epoll.register(client.fileno(), select.EPOLLIN)
# 添加对应关系
fd_socket[client.fileno()] = client
# 读就绪
elif event == select.EPOLLIN:
data = sock.recv(2018)
if not data:
# 注销事件
epoll.unregister(fd)
# 关闭socket
sock.close()
# 删除socket对应关系
del fd_socket[fd]
print(" somebody fuck out...")
continue
print(data.decode("utf-8"))
# 读完数据 需要把数据发回去所以接下来更改为写就绪=事件
epoll.modify(fd, select.EPOLLOUT)
#记录数据
msgs.append((sock,data.upper()))
elif event == select.EPOLLOUT:
for item in msgs[:]:
if item[0] == sock:
sock.send(item[1])
msgs.remove(item)
# 切换关注事件为写就绪
epoll.modify(fd,select.EPOLLIN)
2.客户端
#coding:utf-8
#客户端
#创建客户端socket对象
import socket
clientsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#服务端IP地址和端口号元组
server_address = ('127.0.0.1',1688)
#客户端连接指定的IP地址和端口号
clientsocket.connect(server_address)
while True:
#输入数据
data = raw_input('please input:')
if data == "q":
break
if not data:
continue
#客户端发送数据
clientsocket.send(data.encode("utf-8"))
#客户端接收数据
server_data = clientsocket.recv(1024)
print ('客户端收到的数据:',server_data)
#关闭客户端socket
clientsocket.close()
三、数据库
1.数据库是什么
1.存放数据的仓库
2.存放数据的其他容器:列表、字典...实在内存中。优点:速度快;缺点:断电丢失
3.文件存储。优点:永久保存;缺点:速度慢
4.数据库的本质:基于CS架构(客户端/服务端)的程序,最终会将数据存储在服务端的磁盘上
2.为什么使用数据库
1.解决直接使用文件存储带来的问题
2.文件存储的问题:
-
1.速度慢
-
2.由于单台机器性能肯定有上限,通过数据库联网的特性,可以用多个机器共同完成数据存储和操作的任务,如果是将数据以文件的形式分布在不同的机器上,处理起来则会比较麻烦,效率低
-
3.不方便用户权限管理
-
**4.多个客户端并发访问,数据很难保证安全 ****
3.服务器架构:
-
1.分布式:每个服务器提供不同的服务(有时候某个业务流程也可能会涉及到多个服务器)
-
1.优点: 耦合度降低 易维护
-
**2.缺点:通讯繁琐,容灾性没有集群好 **
-
-
2.集群:所有服务器提供的服务是一模一样的
- 优点:容灾性强,易扩展,可插拔
通过网络 访问
3.数据库的分类
1.关系型数据库
1.数据之间可以存在关联关系,关系型数据库会帮我们维护这种关系
2.通常存储介质都是磁盘
3.常见的关系型型数据库:
# mysql
是我们学习的重点,是目前最流行的关系型数据库,因为其免费开源,性能不错
目前已经被oracle收购了,适用于中小型企业
# sqlserver
是微软推出的, 因为其只能运行在windows平台所以发展不咋地
# oracle
目前最强大的关系型数据库,主要是在集群,和用户管理上,非常适合大型企业
# db2
IBM的产品,主要面向企业级用户,不差钱的用户 捆绑硬件销售
2.非关系型数据库
1.一般不帮我们维护数据之间的关系
**2.通常存储介质都是内存 **
3.常见的非关系型:
mongoDB
redis
memcache
4.数据库的重要概念
1.字段/具体数据(Column:列):文件中的某个字符串,比如,姓名:King
2.记录(Row:行):文件中的某一行,比如,姓名:King,年龄:26,性别:male
3.表(Table):某个文件。库下面有多个文件,比如,mysql文件夹中的user.MYD文件。这些文件中存放着多行记录
4.库(DataBase):某个文件夹。数据库软件中有多个文件夹,比如,mysql文件夹
5.DBMS:数据库管理系统(就是数据库软件,比如:mysql-5.6.43-winx64)
**6.数据库服务器:运行DBMS的计算机(在电脑上搜索“服务”)
5.数据库的安装和简单使用
1.bin中存储所有执行文件(mysqld.exe是服务端,mysql.exe是客户端)
2.data中存储数据:文件夹(库)--文件(表)
3.运行客户端时,如果直接双击运行是进入游客模式,正确的运行方式是,在终端里指定用户名密码等参数:
-h 主机名称 如果是本机 可以忽略
-P(大写) 指定端口 默认3306 可以不写
-u 指定用户名
-p(小写) 指定密码
# -h127.0.0.1 -P3306 -uroot -p
4.添加环境变量:
1.将bin的路径复制到系统环境变量中
2.通过cmd管理员权限:注册系统服务,cmd中输入 mysqld --install
5.一些简单操作:
# cmd中输入
1.如果之前装过mysql,想卸载:sc delete mysql(注意:mysql是服务名称不是文件名称)
2.启动服务 net start mysql;
3.停止服务 net stop mysql;
4.查找某个进程 tasklist | findstr mysqld
5.杀死进程 taskkill /f /pid 111111
6.mysql 5.6管理员密码的设置
1.知道原始密码
- 1.1登录到mysql 执行更新语句来修改:
# 在MySQL下写SQL语句,注意末尾加分号
1.先use mysql之后;
2.再输入 update user set password = password("123") where host="localhost" and user="root";
3.刷新全新 flush privileges;
3.或者重启mysqld;()
- 2.2 mysqladmin小工具:
# 在cmd中输入不需要加分号
1.mysqladmin -uroot -p123 password 321
2.注意:-p是原始密码
**2.不知道原始密码 **
-
2.1删除权限相关的文件 (容易挨打)
-
2.2 跳过授权表:
# 1.手动启动mysqld 指定参数
在cmd中输入 mysqld --skip-grant-tables
# 2.开启一个客户端
在mysql中输入 use mysql;
再输入update user set password = password("111") where host="localhost" and user="root";
# 3.重启mysqld 即可
7.库和表的增删改查
1.数据必须存在表(文件)中,表必须存在库(文件夹)中
1.库的操作
- 1.不区分大小写
- 2.不要使用关键字 例如create select 等.....
- 3.不能使用纯数字
- 4.可以下滑线 通常字符下滑线数字的组合
# 均在MySQL中输入SQL语句(注意加分号)
# 1.切换数据库(可以在库中切换到其他库)
use 数据库名称(可以不加分号)
# 2.增加库
create database 数据库名称 charset urf8 /*创建库*/;
# 3.查看所有数据库
show databases #查看有哪些库;
# 4.查看数据客详细信息
show create database 数据库名称 -- 查看mydb库的详细信息;
# 5.删除数据库
drop database 数据库名称
# 6.修改数据库编码 可以进入到数据库文件夹中修改db.opt
# 第一行是编码 第二行是排序规则 自己搜索一个
# 7.修改数据库名 可以直接修改对应的文件夹名称
2.表的操作
# 1.查看当前库下的所有表
show tables -- 需要先 use 库名 之后;
# 2.查看单个表的结构(内容)
desc 表名称;
# 3.查看表的创建语句(如何写的,我们要注意的规范)
show create table 表名称;
# 4.创建表(注意列的数据类型有char、text、int...但是没有str/string类型)
create table 表名称(列名称1 列1的数据类型, 列名称2 列2的数据类型,...) charset gbk;
# 5.修改表的名称
rename table 旧名称 to 新名称;
# 6.修改表的编码
alter table 表名 charset utf8 -- 注意:在MySQL中只能写'utf8',别写‘utf-8';
# 7.删除表
drop table 名称;
# 8.修改表的结构(内容)
## 8.1 添加字段(列)
alter table 表名 add 列名 数据类型:
## 8.2 删除字段(列)
alter table 表名 drop 列名:
## 8.3 修改字段(列)的数据类型
alter table 表名 modify 列名 新的数据类型:
## 8.4 修改字段(列)名、数据类型
alter table 表名 change 旧列名 新列名 新数据类型:
# 9.清空表数据
truncate table 表名;
3.注释
# 1.#注释内容
show databases #注释内容;
# 2.-- 注释内容(注意--后面必须空一格)
show databases -- 注释内容;
# 3./*注释内容*/
show databases /*注释内容*/;