day02
注意:只有必答题部分计算分值,补充题不计算分值。
-
简述 OSI 7层模型及其作用?(2分)
应用层 表示层 会话层 传输层 网络层 数据链路层 物理层
一般在开发中应用层 表示层 会话层会合并成应用层
我们开发中的网络通信都是基于socket来完成的,它封装了传输层 网络层 数据链路层 物理层各层的功能
大概包括 :
• 应用层 : 是计算机用户以及各种应用程序和网络之间的接口,直接向用户提供服务,完成用户所需的在网络上的各种工作 ,应用层为用户提供的服务和协议有:文件服务、目录服务、文件传输服务(FTP)、远程登录服务(Telnet)、电子邮件服务(E-mail)、打印服务、安全服务、网络管理服务、数据库服务等
• 表示层 : 处理用户信息的表示问题,如编码、数据格式转换和加密解密”等。
• 会话层 : 组织和协调两个会话进程之间的通信,并对数据交换进行管理。
• 传输层 : 接收上一层的数据,在必要时吧数据进行分割,并将这些数据交给网络层,且保证这些数据段有效到达对端
• 网络层 : 控制子网的运行,如逻辑编址、分组传输、路由选择
• 数据链路层 : 通过各种控制协议,将有差错的物理信道变为无差错的、能可靠传输数据帧的数据链路。
• 物理层 : 利用物理传输介质为数据链路层提供物理连接,实现比特流的传输 -
简述 TCP三次握手、四次挥手的流程。(3分)
三次握手
TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口大小信息。
(1)第一次握手:Client将标志位SYN置为1,产生一个随机值seq=x,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
(2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack (number )=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
(3)第三次握手:Client收到确认后,检查ack是否为Client发送的seq+1,即x+1;如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给Server。Server检查ack是否为Server发送的seq+1,即y+1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手。四次挥手
当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的,那对于TCP的断开连接,这里就有了神秘的“四次挥手”。
(1)第一次挥手:客户端设置seq=x,向服务端发送一个FIN = 1报文段;此时,主机1进入FIN_WAIT_1状态;这表示客户端没有数据要发送给服务端了;
(2)第二次挥手:服务端收到了客户端发送的FIN=1,向客户端回复ACK=1,ack=收到的seq+1=x+1,然后客户端进入FIN_WAIT_2状态;服务端告诉客户端,在等待自己去关闭连接;
(3)第三次挥手:服务端向客户端发送FIN=1,设置seq=y,请求关闭连接,同时服务端进入LAST_ACK状态;
(4)第四次挥手:客户端收到服务端发送的FIN,向服务端发送ACK=1,ack=收到的seq+1=y+1,然后主机1进入TIME_WAIT状态;服务端收到客户端的ACK报文段以后,就关闭连接;此时,客户端等待2MSL后依然没有收到回复,则证明Server端已正常关闭,客户端也关闭连接。 -
TCP和UDP的区别?(3分)
tcp 面向连接 传输可靠 速度慢
udp 面向报文 可靠性差 速度快
-
什么是黏包?(2分)
tcp协议数据无边界的特点 导致了多条分散发送的数据粘合在一起变成了一条数据
-
什么 B/S 和 C/S 架构?(2分)
web 项目 B/S
C/S 桌面端
-
请实现一个简单的socket编程(客户端和服务端可以进行收发消息)(3分)
server.py
#UDP
#时间同步服务: 客户端主动发送时间格式. 服务端根据格式返回当前时间
import socket
import time
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',10000))
while 1:
msg,addr=sk.recvfrom(1024)
print(f'{msg.decode("utf-8").split(".")[0]}客户端要求时间格式为:{msg.decode("utf-8")},客户端的IP地址为{addr}')
my=time.strftime(msg.decode('utf-8').split('.')[1],time.localtime(time.time()))
sk.sendto(my.encode('utf-8'),addr)
client.py
import time
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
addr=('127.0.0.1',10000)
while 1:
my=input("请输入时间格式,例如(%Y-%m-%d %H:%M:%S):").strip()
if my.lower()=='q':
break
sk.sendto(f'\033[1;31;40m田岗. {my}\033[0m'.encode('utf-8'),addr)
print(sk.recv(1024).decode('utf-8')) -
简述进程、线程、协程的区别?(3分)
进程 : 开销大 数据隔离 子进程中有一个挂了不影响其他的 cpython可以利用多核 高计算型
线程 : 开销小 数据共享 子线程中挂了一个会影响其他 cpython不能利用多核 高IO型(文件操作/网络操作)
协程 : 只能针对高IO型 且是网络IO才能有并发作用 用户级别的 开销更小
-
什么是GIL锁?(2分)
全局解释器锁 ,本身就是一把互斥锁,将并发变成串行,同一时刻,只能有一个线程去使用共享资源,牺牲了效率,保证了数据的安全
-
进程之间如何进行通信?(2分)
IPC:基于第三方工具(redis) 基于管道 队列
-
Python如何使用线程池、进程池?(2分)
concurrent.futures.ThreadPoolExecutor
concurrent.futures.ProcessPoolExecutor
-
请通过yield关键字实现一个协程? (2分)
def consumer():
while True:
n = yield
print('处理数据%s' % n)
def producer():
cg = consumer()
next(cg)
for i in range(100):
print('生产了一个%s'%i)
# yield i # 每生产一个数据就停止
cg.send(i)
producer() -
什么是异步非阻塞? (2分)
同步join input 异步 : terminate
阻塞不占用cpu 非阻塞 :占用cpu
同步阻塞 : name = input() ;pwd = input()
同步非阻塞 : say();say2()
异步阻塞 : 比如启动多线程和多个客户端进行tcp通信
可以同时和多个人通信,但是每个人的通信中recv仍然会发生阻塞
异步非阻塞 : 可以启动多线程 设置setblocking(False)
可以同时和多个人通信,并且在过程中没有阻塞
-
什么是死锁?如何避免?(2分)
用一把锁 : 一把递归锁 /一把互斥锁
-
程序从flag a执行到falg b的时间大致是多少秒?(2分)0
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait)
t.setDeamon(False)
t.start()
# flag b -
程序从flag a执行到falg b的时间大致是多少秒?(2分) 0
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait)
t.setDeamon(True)
t.start()
# flag b -
程序从flag a执行到falg b的时间大致是多少秒?(2分)60
import threading import time def _wait(): time.sleep(60) # flag a t = threading.Thread(target=_wait) t.start() t.join() # flag b
-
读程序,请确认执行到最后number是否一定为0(2分) 一定
import threading loop = int(1E7) def _add(loop:int = 1): global number for _ in range(loop): number += 1 def _sub(loop:int = 1): global number for _ in range(loop): number -= 1 number = 0 ta = threading.Thread(target=_add,args=(loop,)) ts = threading.Thread(target=_sub,args=(loop,)) ta.start() ta.join() ts.start() ts.join()
-
读程序,请确认执行到最后number是否一定为0(2分) 不一定
import threading loop = int(1E7) def _add(loop:int = 1): global number for _ in range(loop): number += 1 def _sub(loop:int = 1): global number for _ in range(loop): number -= 1 number = 0 ta = threading.Thread(target=_add,args=(loop,)) ts = threading.Thread(target=_sub,args=(loop,)) ta.start() ts.start() ta.join() ts.join()
-
MySQL常见数据库引擎及区别?(3分)
innodb 5.6之后的默认 : 支持行级锁 事务 外键
开启事务 查询这个用户还是不是一个公户+锁,如果是改成私户 提交事务
select xxx from 表 where id = 1 for update
myisam 5.5之前的默认 只支持表锁
memory 内存
blackhole 黑洞
create table 表名() charset=utf8 engine=blackhole;
-
简述事务及其特性? (3分)
一致性 原子性 隔离性 持久性
-
事务的隔离级别?(2分)
脏读,幻读,不可重复读
未提交读\已提交读\可重复读\串行化
-
char和varchar的区别?(2分)
定长 255 高效 浪费空间
变长 65535 低效 节省空间
-
mysql中varchar与char的区别以及varchar(50)中的50代表的含义。(2分) 最长50个字符
-
MySQL中delete和truncate的区别?(2分)
delete :可以删除部分数据 auto_incement清除不掉
truncate :清空表 并且重置auto_increment为0
-
where子句中有a,b,c三个查询条件, 创建一个组合索引abc(a,b,c),以下哪种会命中索引(3分)
(a) 这个 (b) (c) (a,b) 这个 (b,c) (a,c) 这个 (a,b,c) 这个
-
组合索引遵循什么原则才能命中索引?(2分)
最左前缀原则 不能用范围 只能用and
-
列举MySQL常见的函数? (3分)
count sum avg max min now year month day hour minute second week sub_date
concat group_count concat_ws user password database
-
MySQL数据库 导入、导出命令有哪些? (2分)
mysqldump
mysqldump -database
source
-
什么是SQL注入?(2分)
通过一些输入的内容绕过sql的判断机制
-
简述left join和inner join的区别?(2分)
-
SQL语句中having的作用?(2分)
以聚合函数作为条件过滤分组
-
MySQL数据库中varchar和text最多能存储多少个字符?(2分)65535
-
MySQL的索引方式有几种?(3分)
主键索引 唯一索引 普通索引 联合主键 联合唯一 联合普通
b+树(innodb) hash索引(memory) 全文索引(Full-text)
b+树(聚合索引 辅助索引)
-
什么时候索引会失效?(有索引但无法命中索引)(3分)
-
数据库优化方案?(3分)
读写分离
分库分表
用定长字段代替变长字段
建表的时候把短的 固定长度的字段放在左边
-
什么是MySQL慢日志?(2分)
-
设计表,关系如下: 教师teacher, 班级class, 学生student, 科室post。(4分) 科室与教师为一对多关系, 教师与班级为多对多关系, 班级与学生为一对多关系, 科室中需体现层级关系。
1. 写出各张表的逻辑字段 2. 根据上述关系表 a.查询教师id=1的学生数 b.查询科室id=3的下级部门数 c.查询所带学生最多的教师的id
select count(*) from student s,class c,teacher t where
s.cid=c.cid and c.cid = t.cid
and tid=1;
select count(*) from post where parent_id=3;
select tid,count(*) as p from student s,class c,teacher t where
s.cid=c.cid and c.cid = t.cid group by tid order by p limit 1;
-
有staff表,字段为主键Sid,姓名Sname,性别Sex(值为"男"或"女"),课程表Course,字段为主键Cid,课程名称Cname,关系表SC_Relation,字段为Student表主键Sid和Course表主键Cid,组成联合主键,请用SQL查询语句写出查询所有选"计算机"课程的男士的姓名。(3分)
-
根据表关系写SQL语句(10分)
-
查询所有同学的学号、姓名、选课数、总成绩;
-
查询姓“李”的老师的个数;
-
查询平均成绩大于60分的同学的学号和平均成绩;
-
查询有课程成绩小于60分的同学的学号、姓名
-
删除学习“叶平”老师课的score表记录;
-
查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;
-
查询每门课程被选修的学生数;
-
查询出只选修了一门课程的全部学生的学号和姓名;
-
查询选修“杨艳”老师所授课程的学生中,成绩最高的学生姓名及其成绩;
-
查询两门以上不及格课程的同学的学号及其平均成绩;
-
第二部分 补充题
-
什么是IO多路复用?
网络数据传输监控机制 - 多个网络连接复用一个监听机制
select模块\selectors模块
操作系统提供的io多路复用的机制 select poll epoll
epoll最好 用的是回调函数的机制
select poll 的内部机制 是 轮询
-
async/await关键字的作用?
async用来定义一个协程函数的
await用来控制一个可能发生io阻塞的任务的切入和切出
async def func():pass await asyncio.sleep(2) import asyncio loop = asyncio.get_event_loop() loop.run_until_complete(func)
-
MySQL的执行计划的作用?
不执行sql,在之前先查看以下sql的顺序 索引的使用情况 从而去推测 优化sql语句
4.简述MySQL触发器、函数、视图、存储过程?
触发器 trigger:在用户对某张表做完某个固定的操作(insert update delete) 会自动在数据库中触发另一个动作
insert 一条数据 苹果手机
往对应的统计表中 把苹果这条数据 +1
函数(function):根据参数进行判断 循环 得出一个结果 并返回,通过select 函数名(参数)来调用并查看结果
视图(view) : 帮助我简化查询部分的连表操作
存储过程(procedure): 可以实现非常负责的sql逻辑 并对数据进行增删改查 且可以返回多个结果 call 名字(参数)调用
5.数据库中有表:t_tade_date
id tade_date 1 2018-1-2 2 2018-1-26 3 2018-2-8 4 2018-5-6 ... 输出每个月最后一天的ID
select last_day(tade_date) from t_tade_date group by month(tade_date) ;
select id from t_tade_date where tade_date in (select last_day(tade_date) from t_tade_date group by month(tade_date));
select id,max(tade_date) from t_tade_date group by month(tade_date) ;