网络编程:
1、 什么是socket?
- 应用层与TCP/IP协议通信的中间软件抽象层,就是一组接口
2、为甚么用socket?
- 用socket是为了完成C/S架构
3、osi七层协议
- 应用层
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 网络接口层
- 数据链路层
- 物理层
4、简述TCP协议的三次握手、四次挥手(C(客户端),S(服务端))
- 三次握手的目的是为了建立一个双向连接
C--请求-->S--回应/请求-->C--回应-->S 建立连接
- 传输数据
- 四次挥手的目的是为了断开连接
C--数据传完,请求断连接-->S--回应/断开连接
S--数据传完,请求断连接-->C--回应/断开连接
- 为什么断连接需要四次:客户端与服务端都是在传完数据后才会断开连接
ps:TCP为什么是可靠传输呢?
- TCP在发一个包后会等对方确认才认为发送成功,否则会在发送一个包
5、说一说对TCP/UDP的理解,他们之间有什么区别
6、粘包现象
- 什么是粘包?
- 发生粘包的两种情况:
- 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,
会当做一个包发出去,产生粘包)
- 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了
一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
- 只有TCP有粘包现象,UDP永远不会粘包
原因:TCP是流式协议,不知道啥时候开始,啥时候结束,
而UDP是面向消息的协议,每个UDP段都是一条消息,
应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据。
- 粘包现象的主要原因:所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性
提取多少字节的数据所造成的。
- 解决粘包的方法:问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘
包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总
大小让接收端知晓,然后接收端来一个死循环接收完所有数据
- 使用struct模块将数据转成固定长度的bytes类型,服务端使用struct模块接收
7、简述进程线程协程。
a、进程
- 什么是进程:一个软件正在进行的过程
- 并发:伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
- 并行:同时运行,只有具有多个CPU才能实现并行
- 同步执行:一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行
- 异步执行:一个进程在执行某个任务时,另外一个进程无需等待其执行完毕,就可以继续执行,
当有消息返回时,系统会通知后者进行处理,这样可以提高执行效率
- 创建进程
1. 系统初始化
2. 一个进程在运行过程中开启了子进程
3. 用户的交互式请求,而创建一个新进程
4. 一个批处理作业的初始化
- 终止进程
1. 正常退出
2. 出错退出
3. 严重错误
4. 被其他进程杀死
多进程
- 互斥锁:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,
即串行的修改,没错,速度是慢了,牺牲了速度而保证了数据安全。
- 什么是生产者消费者模式
- 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。
- 在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。
- 数据共享
- 进程池:进程池就是控制进程数目
- 回调函数
- 需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:
我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数
即回调函数
b、线程
- 线程:顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
- 多线程:在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。(一个进程里面开多个线程(共享同一个进程里面的内存空间))
- 进程与线程的区别:
- 创建线程比进程开销小
- 多线程一定是在一个进程里边开启的,共享进程里的资源
- 线程启动的速度快
- 同一进程下的多个线程共享进程的资源,而多个进程之间内存空间是隔离的
- 线程可以跟他所在的进程之内的线程通信
- 多线程:在一个进程中开启多个线程。
- 为什么使用多线程(如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程)
- 多线程共享一个进程的地址空间
- 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比
创建一个进程要快10-100倍,再有大量线程需要动态和快速修改时,这一特性很有用
- 若多个线程都是CPU密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大
量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度
- 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。
- 锁
- 守护进程与守护线程的区别?
- 守护进程:主进程会等到所有的非守护进程结束,才销毁守护进程
- 守护线程:主线程运行完了守护的那个还没有干掉,主线程等非守护线程全部结束他才结束。
- GIL与Lock(互斥锁)
- 锁的目的:牺牲效率,保证数据的安全
- GIL 与Lock是两把锁,保护的数据不一样,前者是解释器级别的(当然保护的就是解释器级别的数据,
比如垃圾回收的数据),后者是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事,
只能用户自定义加锁处理,即Lock
- 加锁导致串行运行的结果,与join方法效果相似,不同的是join锁住的是所有代码、而Lock只是锁住一部分操作共享数据的代码
- 总结:
- 不加锁:并发执行,速度快,数据不安全
- 加锁:串行执行,速度慢,数据安全
- 死锁现象:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,
若无外力作用,他们都将无法推进下去,此时称系统处于死锁状态或系统产生了死锁。
- 解决死锁现象:递归锁:在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
- 信号量Semaphore管理一个内置的计数器
- Semaphore与进程池的区别
- 进程池:Pool(4),最大只能产生四个进程,而且从头到尾都只是这四个进程,不会产生新的
- 信号量:是产生的一堆进程/线程,即产生多个任务都去抢那一把锁
- 线程的一个关键特性是每个线程都是独立运行且状态不可预测
- 实现并发的方式
- 一个进程下,开多个线程
- 开多个进程
- 多进程与多线程优缺点
- 多进程:优:可以利用多核,缺:但开销大。应用场景:计算密集型
- 多线程:优:开销小,缺:不可以利用多核。应用场景:IO密集型
c、协程
- 进程池:就是在一个进程内控制一定个数的线程
- 协程:单线程下实现并发(提高效率)
- 协程的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行,以此来提升效率。
8、IO模型(实现遇到IO就切换的功能)
- 同步调用:一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行
- 异步调用:一个进程在执行某个任务时,不需要等待这个进程结束就去执行下一个进程。
- 阻塞:是指调用结果返回之前,当前线程/进程会被挂起,只有在得到结果之后才会将阻塞的线程/进程激活
- 非阻塞:指在不能立刻得到结果之前也会立刻返回,同时该函数不会阻塞当前线程。
- 阻塞IO(blocking IO)的特点:就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。
- IO多路复用(select)
- select检测的是哪个套接字准备好了(检测的时候等待了,变成阻塞了)
- select之所以比阻塞IO好,就是因为select可以检测多个套接字
- 多个链接下select才能发挥它的优势
- 但是你的套接字特别多,你怎么知道哪个好了呢,那么就得用循环去遍历一下
- 那么如果特别多的时候,效率也就不咋高了
- eppol:只支持linux系统(就是为了解决select效率低的问题)
- eppol比pool,select效率高
- selectors 更好用,解决了上面select,eppol,pool的问题
- socketserver用这个模块IO问题也解决了,实现并发也解决了
问题:
- 守护线程/进程
- 守护进程:存在的意义是为了提供守护给主进程某种功能
(例如运行一个软件,为了检测这个软件是否存活,添加一检测功能检测软件,
软件一旦停止,守护进程(即检测功能)停止销毁)
- 主进程附加功能:把子进程(非守护进程)回收掉才能结束
- 主进程等子进程运行完才结束 是为了回收子进程
- 主线程等其他线程结束是为了保证其他线程能够正常运行结束(主线程支持其他线程的运行)
- 线程与进程的区别?
- 主进程是在代码运行完后结束,主线程是在所有非守护线程结束后才结束
- 如何实现高并发
- 高并发:同一时间内,大量的请求服务器,这个大量一般是指千万级以上的请求次数。
- 实现方法:
- Nginx要做负载均衡
- 程序层面做多线程,锁等机制
- 数据库层面处理
- 服务器配置要尽量高
- IO多路复用(select)
数据库:
- 数据库简介
- 关系型数据库管理系统:MySQL、db2、sqlite
- 非关系型:mongodb、redis、memcache
- 存储引擎
- 就是表的类型,不同的类型就会对应不同的处理机制去处理他
- 就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法
- 事务:就是(二十条数据)要么同时成功,要么同时不成功
例如:转账-一边减钱、一边加钱,这两个事件要同时完成
- mysql默认端口3306
- 简单查询
- 多表查询
- 交叉连接:不适用任何匹配条件。生成笛卡尔积、
- select * from employee1 ,department;
- 内连接:找两张表共有的部分。
- select * from employee1,department where employee1.dep_id=department.id;
# 推荐用下边这种
- select * from employee1 inner join department on employee1.dep_id=department.id;
注意:内连接的inner可以忽略不写,但是还是加上看起来清楚点
- 左连接:优先显示左表全部记录。
- select * from employee1 left join department on department.id=employee1.dep_id;
#左链接:在按照on的条件取到两张表共同部分的基础上,保留左表的记录
- 右链接:优先显示右表全部记录。
- select * from employee1 right join department on department.id=employee1.dep_id;
#右链接:在按照on的条件取到两张表共同部分的基础上,保留右表的记录
- 全外连接:显示左右两个表的全部记录。
- select * from employee1 left join department on department.id=employee1.dep_id
union
select * from employee1 right join department on department.id=employee1.dep_id;
注意:mysql不支持全外连接 full join
强调:mysql可以使用union间接实现全外连接
- 符合条件连接查询:
- 即找出公司所有部门中年龄大于25岁的员工
- select * from employee1 inner join department on employee1.dep_id=department.id
and age>25;
- 子查询
- 1:子查询是将一个查询语句嵌套在另一个查询语句中。
- 2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
- 3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
- 4:还可以包含比较运算符:= 、 !=、> 、<等
- #查询平均年龄在25岁以上的部门名
- select name from department where id in (
select dep_id from employee group by dep_id having avg(age) > 25
);
- #查看技术部员工姓名
- select name from employee where dep_id = (select id from department where name='技术');
- 索引
- 索引:就像书的目录
- 本质原理:不断缩小范围
- 只提升读的速度
- 操作:
- 1.创建索引
-在创建表时就创建(需要注意的几点)
create table s1(
id int ,#可以在这加primary key
#id int index #不可以这样加索引,因为index只是索引,没有约束一说,
#不能像主键,还有唯一约束一样,在定义字段的时候加索引
name char(20),
age int,
email varchar(30)
#primary key(id) #也可以在这加
index(id) #可以这样加
);
-在创建表后在创建
create index name on s1(name); #添加普通索引
create unique age on s1(age);添加唯一索引
alter table s1 add primary key(id); #添加住建索引,也就是给id字段增加一个主键约束
create index name on s1(id,name); #添加普通联合索引
2.删除索引
drop index id on s1;
drop index name on s1; #删除普通索引
drop index age on s1; #删除唯一索引,就和普通索引一样,不用在index前加unique来删,直接就可以删了
alter table s1 drop primary key; #删除主键(因为它添加的时候是按照alter来增加的,那么我们也用alter来删)
- 注意点:
- 字段要短
- 自左向右
- 创建索引要找区分度最高的字段来建
- 索引合并是指用or时给每个单独的字段加上索引
- 组合索引是针对and时添加联合索引
- 数据库备份
- 物理备份
- 逻辑备份
- 导出表
- pymysql
- 使用示例
import pymysql
user= input('用户名:>>').strip()
pwd= input('密码:>>').strip()
#先链接,拿到游标
conn=pymysql.connect(host='localhost',user='root',password='123456',
database='day47',charset='utf8')
cursor=conn.cursor() #拿到游标,即mysql >
#执行sql
sql='select * from user where user="%s" and password="%s";'%(user,pwd)
print(sql) #注意%s需要加双引号
rows = cursor.execute(sql) #拿到受影响的行数
cursor.close()
conn.close()
if rows:
print('登录成功')
else:
print('登录失败')
- sql注入
- 注意:符号--会注释掉它之后的sql,正确的语法:--后至少有一个任意字符
- 根本原理:就根据程序的字符串拼接name='%s',我们输入一个xxx' -- haha,
用我们输入的xxx加'在程序中拼接成一个判断条件name='xxx' -- haha'
- 解决注入
# 原来是我们对sql进行字符串拼接
# sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd)
# print(sql)
# rows=cursor.execute(sql)
#改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
sql="select * from userinfo where name=%s
and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
rows=cursor.execute(sql,[user,pwd])
#pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
- 增删改:conn.commit()
- 查:fetchone,fetchmany,fetchall
- 视图(不推荐使用)
- 视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,
用户使用时只需使用【名称】即可获取结果集,可以将该结果集当做表来使用。
- 注意:
- 对于单表来说是可以修改的,并且原来表的也就更改了。
- 但是一般还是不要这样改。视图大多数是用来查看的
- 创建视图
#建表
CREATE TABLE t1(
id int PRIMARY KEY auto_increment,
name CHAR(10)
);
#插入数据
insert into t1 VALUES (1,'egon'),
(2,'daa'),
(3,'eef');
#创建视图
CREATE view t1_view as select * from t1;
#测试创建视图以后还能不能增删改查
select * from t1_view;
update t1_view set name = '东风' where id = 2; #可以修改(而且原来表的记录也修改了)
INSERT into t1_view values(4,'aaa'); #可以插入(同上)
delete from t1_view where id=3;#同上
#修改视图
alter view 视图名称 as sql语句
#删除视图
- drop view 视图名称
- 存储过程
- 封装sql语句,应用程序可以调用
- 问题总结:
1、mysql如何做分页
mysql数据库做分页用limit关键字,它后面跟两个参数startIndex和pageSize
2、mysql引擎有哪些,各自的特点是什么?
innodb和myisam两个引擎,两者区别是
innodb支持事物,myisam不支持
innodb支持外键,myisam不支持
innodb不支持全文索引,myisam支持全文索引
innodb提供提交、回滚、崩溃恢复能力的事物的安全能力,实现并发控制
myisam提供较高的插入和查询记录的效率,主要用于插入和查询
3、数据库怎么建立索引
create index account_index on `table name `(`字段名`(length)
4、一张表多个字段,怎么创建组合索引
create index account_index on `table name `(`字段名`,'字段名')
5、如何应对数据的高并发,大量的数据计算
1.创建索引
2.数据库读写分离,两个数据库,一个作为写,一个作为读
3. 外键去掉
4.django中orm表性能相关的
select_related:一对多使用,查询主动做连表
prefetch_related:多对多或者一对多的时候使用,不做连表,做多次查询
6、数据库内连表、左连表、右连表
内连接是根据某个条件连接两个表共有的数据
左连接是根据某个条件以及左边的表连接数据,右边的表没有数据的话则为null
右连接是根据某个条件以及右边的表连接数据,左边的表没有数据的话则为null
7、视图和表的区别
视图是已经编译好的sql语句,是基于sql语句的结果集的可视化的表,而表不是
视图是窗口,表示内容
视图没有实际的物理记录,而表有
视图的建立和删除只影响视图本身,不影响对应的表
8、关系型数据库的特点
数据集中控制
数据独立性高
数据共享性好
数据冗余度小
数据结构化
统一的数据保护能力
9、mysql数据库都有哪些索引
普通索引:普通索引仅有一个功能:加速查找
唯一索引:唯一索引两个功能:加速查找和唯一约束(可含null)
外键索引:外键索引两个功能:加速查找和唯一约束(不可为null)
联合索引:联合索引是将n个列组合成一个索引,应用场景:同时使用n列来进行查询
10、存储过程
存储过程不允许执行return语句,但是可以通过out参数返回多个值,
存储过程一般是作为一个独立的部分来执行,存储过程是一个预编译的SQL语句。
11、sql优化:
select句中避免使用 '*'
减少访问数据库的次数
删除重复记录
用where子句替代having子句
减少对表的查询
explain
12、char和vachar区别:
char是固定长度,存储需要空间12个字节,处理速度比vachar快,费内存空间
vachar是不固定长度,需要存储空间13个字节,节约存储空间
13、Mechached与redis
mechached:只支持字符串,不能持久化,数据仅存在内存中,宕机或重启数据将全部失效
不能进行分布式扩展,文件无法异步法。
优点:mechached进程运行之后,会预申请一块较大的内存空间,自己进行管理。
redis:支持服务器端的数据类型,redis与memcached相比来说,拥有更多的数据结构和并发支持更丰富的数据操作,可持久化。
五大类型数据:string、hash、list、set和有序集合,redis是单进程单线程的。
缺点:数据库的容量受到物理内存的限制。
14、sql注入
sql注入是比较常见的攻击方式之一,针对编程员编程的疏忽,通过sql语句,实现账号无法登陆,
甚至篡改数据库。
防止:凡涉及到执行sql中有变量时,切记不要用拼接字符串的方法
15、什么是触发器
触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的,他可以强化约束,
来维护数据库的完整性和一致性,可以跟踪数据内的操作从而不允许未经许可的更新和变化,
可以联级运算。 只有表支持触发器,视图不支持触发器
16、游标是什么?
是对查询出来的结果集作为一个单元来有效的处理,游标可以定在该单元中的特定行,
从结果集的当前行检索一行或多行,可以对结果集当前行做修改,
一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要
17、数据库支持多有标准的SQL数据类型,重要分为三类
数值类型(tinyint,int,bigint,浮点数,bit)
字符串类型(char和vachar,enum,text,set)
日期类型(date,datetime,timestamp)
18、mysql慢查询
慢查询对于跟踪有问题的查询很有用,可以分析出当前程序里哪些sql语句比较耗费资源
慢查询定义:
指mysql记录所有执行超过long_query_time参数设定的时间值的sql语句,慢查询日志就是记录这些sql的日志。
mysql在windows系统中的配置文件一般是my.ini找到mysqld
log-slow-queries = F:MySQLlogmysqlslowquery.log 为慢查询日志存放的位置,一般要有可写权限
long_query_time = 2 2表示查询超过两秒才记录
19、memcached命中率
命中:可以直接通过缓存获取到需要的数据
不命中:无法直接通过缓存获取到想要的数据,需要再次查询数据库或者执行其他的操作,原因可能是由于缓存中根本不存在,或者缓存已经过期
缓存的命中率越高则表示使用缓存的收益越高,应额用的性能越好,抗病发能力越强
运行state命令可以查看memcached服务的状态信息,其中cmd—get表示总的get次数,get—hits表示命中次数,命中率=get—hits / cmd—get
20、Oracle和MySQL该如何选择,为什么?
他们都有各自的优点和缺点。考虑到时间因素,我倾向于MySQL
选择MySQL而不选Oracle的原因
MySQL开源
MySQL轻便快捷
MySQL对命令行和图形界面的支持都很好
MySQL支持通过Query Browser进行管理
21、什么情况下适合建立索引?
1.为经常出现在关键字order by、group by、distinct后面的字段,建立索引
2.在union等集合操作的结果集字段上,建立索引,其建立索引的目的同上
3.为经常用作查询选择的字段,建立索引
4.在经常用作表连接的属性上,建立索引
22、数据库底层是用什么结构实现的,你大致画一下:
底层用B+数实现,结构图参考:
http://blog.csdn.net/cjfeii/article/details/10858721
http://blog.csdn.net/tonyxf121/article/details/8393545
23、sql语句应该考虑哪些安全性?
1.防止sql注入,对特殊字符进行转义,过滤或者使用预编译的sql语句绑定变量
2.最小权限原则,特别是不要用root账户,为不同的类型的动作或者组建使用不同的账户
3.当sql运行出错时,不要把数据库返回的错误信息全部显示给用户,以防止泄漏服务器和数据库相关信息
24、数据库事物有哪几种?
隔离性、持续性、一致性、原子性
25、MySQ数据表在什么情况下容易损坏?
服务器突然断电导致数据文件损坏
强制关机,没有先关闭mysq服务器等
26、drop,delete与truncate的区别
drop直接删除表
truncate删除表中数据,再插入时自增长id又从1开始
delete删除表中数据,可以加where子句
27、数据库范式
1.第一范式:就是无重复的列
2.第二范式:就是非主属性非部分依赖于主关键字
3.第三范式:就是属性不依赖于其他非主属性(消除冗余)
28、MySQL锁类型
根据锁的类型分:可以分为共享锁、排他锁、意向共享锁和意向排他锁
根据锁的粒度分:可以分为行锁、表锁
对于mysql而言,事务机制更多是靠底层的存储引擎来实现的,因此,mysql层面只有表锁,
而支持事物的innodb存储引起则实现了行锁(在行相应的索引记录上的锁)
说明:对于更新操作(读不上锁),只有走索引才可能上行锁
MVCC(多版本并发控制)并发控制机制下,任何操作都不会阻塞读取操作,
读取操作也不会阻塞任何操作,只因为读不上锁
共享锁:由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排他锁,
也就是说只能读不能写
排他锁:由写表操作加上的锁,加锁后其他用户不能获取该表或该行的任何锁,典型mysql事物中的更新操作
意向共享锁(IS):事物打算给数据行加行共享锁,事物在给一个数据行加共享锁前必须先取得该表的IS锁
意向排他锁(IX):事物打算给数据行加行排他锁,事物在给一个数据行家排他锁前必须先取得该表的IX锁
29、如何解决MYSQL数据库中文乱码问题?
1.在数据库安装的时候指定字符集
2.如果在按完了以后可以更改配置文件
3.建立数据库时候:指定字符集类型
4.建表的时候也指定字符集
30、数据库应用系统设计
1.规划
2.需求分析
3.概念模型设计
4.逻辑设计
5.物理设计
6.程序编制及调试
7.运行及维护