Python是一种具备对象、模块、线程、异常和自动内存管理的编程语言。javascript
Python的好处是它简单、易用、可移植、可扩展、内置数据结构、而且是开源的。
css
PEP8是一种编码规范,中文意思「Python加强建议书」也可叫作「Python改进建议书」这个文档主要是用来规范 Python 代码的写法。html
缩进:4个空格的缩进,不能混合使用Tab和空格。前端
每行最大长度79,换行能够使用反斜杠,最好使用圆括号。vue
类和top-level函数定义之间空两行;类中的方法定义之间空一行;函数内逻辑无关段落之间空一行;其余地方尽可能不要再空行。java
模块导入的顺序:按标准、三方和本身编写顺序依次导入,之间空一行。python
不要在一句import中多个库,好比import os, sys不推荐mysql
避免没必要要的空格jquery
注释必需要有linux
函数命名要遵循规范
尽量使用‘is’‘is not’取代‘==’,好比if x is not None 要优于if x。
使用基于类的异常,每一个模块或包都有本身的异常类,此异常类继承自Exception。
异常中try的代码尽量少。
在 Python3 中,input()获取用户输入,不论用户输入的是什么,获取到的都是字符串类型的。
在 Python2 中有 raw_input()和 input(), raw_input()和 Python3 中的 input()做用是同样的,input()输入的是什么数据类型的,获取到的就是什么数据类型的。
方法一:
方法二:
read:读取整个文件。
readline:读取下一行,使用生成器方法。
readlines:读取整个文件到一个迭代器以供咱们遍历。
会继续处理finally中的代码。
使用raise方法能够抛出自定义异常。
except:捕获全部异常
except: <异常名> 捕获自定异常
except:<异常名1, 异常名2, ...> 捕获多个异常
except: <异常名> , <数据> 捕获指定异常及其附加的数据
except:<异常名1, 异常名2>: <数据> 捕获异常名1或者异常名2,及其附加的数据
系统库:
第三方库:
init在对象建立后,对对象进行初始化。
new是在对象建立以前建立一个对象,并将该对象返回给init。
能够使用Python提供的random模块生成随机数。
举🌰
random.random() 生成一个 0-1 之间的随机浮点数。
random.uniform(a, b) 生成 a-b 之间的浮点数。
random.randint(a, b) 生成 a-b 之间的整数。
random.randrange(a, b, step) 在指定的集合[a, b)中,以step为基数随机取一个数。
random.choice(sequence) 从特定序列中随机取一个元素,这里的序列能够使字符串,列表,元祖等。
os.path主要是用于对系统路径文件的操做。
sys.path主要是对Python解释器的系统环境参数的操做(动态的改变Python解释器搜索路劲)。
方法太多,挑几个容易记的
os.remove()删除文件
os.rename()重命名文件
os.walk()生成目录树下的全部文件名
os.chdir()改变目录
os.mkdir/makedirs 建立目录/多层目录
os.rmdir/removedirs 删除目录/多层目录
os.listdir()列出指定目录的文件
os.getcwd()取得当前工做目录
os.chmod()改变目录权限
os.path.basename()去掉目录路径,返回文件名
os.path.dirname()去掉文件名,返回目录路径
os.path.join()将分离的各部分组合成一个路径名
os.path.split()返回(dirname(),basename())元组
os.path.splitext()(返回 filename,extension)元组
os.path.getatime\ctime\mtime 分别返回最近访问、建立、修改时间
os.path.getsize()返回文件大小 • os.path.exists()是否存在
os.path.isabs()是否为绝对路径
os.path.isdir()是否为目录
os.path.isfile()是否为文件
方法太多,挑几个容易记的
sys.exit(n) 退出程序,正常退出时 exit(0)
sys.version 获取 Python 解释程序的版本信息
sys.argv 命令行参数 List,第一个元素是程序自己路径
sys.modules.keys() 返回全部已经导入的模块列表
sys.argv 命令行参数 List,第一个元素是程序自己路径
sys.maxint 最大的 Int 值
sys.path 返回模块的搜索路径,初始化时使用 PYTHONPATH 环境变量的值
sys.platform 返回操做系统平台名称
sys.stdout 标准输出
sys.stdin 标准输入
sys.stderr 错误输出
sys.path 返回模块的搜索路径,初始化时使用 PYTHONPATH 环境变量的值
在Python中,模块是搭建程序的一种方式。每个Python代码文件都是一个模块,并能够引用其余的模块,好比对象和属性。
一个包包含许多Python代码的文件夹就是一个包。一个包能够包含模块和子文件夹。
Python是强类型的动态脚本语言。
强类型:不容许不一样类型相加
动态:不须要声明数据类型,且肯定一个变量的类型是在第一次给它赋值的时候。
脚本语言:通常也是解释型语言,运行diamante只须要一个解释器,不须要编译。
解释型语言在程序运行的时候才会进行翻译。
编译型语言在执行以前,须要一个专门的编译过程,把程序编译成机器语言(可执行文件)。
使用多线程,充分利用机器的多核性能。
对于性能影响较大的部分代码,能够使用 C 或 C++ 编写。
对于 IO 阻塞形成的性能影响,能够使用 iO 多路复用来解决。
尽可能使用 Python 的内建函数。
尽可能使用局部变量。
字典
列表
元祖
集合
set:集合,在Python中的书写方式为大括号"{}",集合与以前的列表、元祖相似,能够储存多个数据,可是这些数据是不能够重复的。
集合对象支持union(联合)、intersection(交)、difference(差)和sysmmetric_difference(对称差集)等数学运算
字典是一种数据结构,json是一种数据的表现形式。
字典的key值只要是能hash的就行,json的必须是字符串。
可变不可变指的是内存中的值是否能够被改变
不可变类型指的是对象所在内存块里面的值不能够改变,如:数值、字符串、元祖
可变类型则是能够改变,如:列表、字典
有三种不一样的含义
转义字符
路径名中用来链接路径名
代码太长手动软换行
类方法:是类对象的方法,在定义时须要在上方使用”@classmethod“进行装饰,形参为cls,表示类对象,类对象和示例对象均可调用。
类实例方法:是类实例化对象的方法,只有实例对象能够调用,形参为self,指表明对象自己。
静态方法:是一个任意函数,在其上方使用”@staticmethod“进行装饰,能够用对象直接调用;静态方法实际上跟该类没有太多的关系。
Python内存由Python专用堆空间管理。全部Python对象和数据结构都位于私有堆中。程序员无权访问此私有堆,解释器负责处理此Python私有堆。
为Python对象分配Python堆空间是由Python内存管理器完成的。核心API容许访问一些工具,以便程序员进行编码。
Python还具备一个内置的垃圾收集器,该垃圾收集器回收全部未使用的内存,并释放内存并使之可用于堆空间。
内存泄漏是指因为疏忽或错误形成程序未能释放已经再也不使用的内存。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后因为设计错误,失去对该段内存的控制,所以形成了内存的浪费;致使程序运行速度减慢甚至系统崩溃等严重后果。
当不使用对象时能够使用:del object来删除一个对象的引用计数就能够有效防止内存泄漏问题。
Python的参数传递有:位置参数、默认参数、可变参数、关键字参数。
函数究竟是值传递仍是引用传递要看实际状况。
缺省参数指在调用函数的时候没有传入参数的状况下,调用默认的参数,在调用函数的同时赋值时所传入的参数会替代默认参数。
*args 是不定长参数,表示传入参数是不肯定的;能够是任意多个。
**kwargs 是关键字参数,赋值的时候是以键 = 值的方式,参数是能够任意多对;在定义函数的时候不肯定会有多少个参数传入时就能够使用两个参数。
内建类型:布尔类型、数字、字符串、列表、元祖、字典、集合
输出字符串 ‘a’ 的内建方法
lambda 是一个匿名函数,它能够接受任意多个参数(包括可选参数)而且返回单个表达式值得函数。
lambda 函数的好处:
lambda 函数比较轻便,即用即扔,很适合须要完成一项功能,可是此项功能只在此一处使用,连名字都很随意的状况下。
匿名函数,通常用来给 filter,map 这样的函数式编程服务。
做为回调函数,传递给某些应用;好比消息处理。
概念:单例模式是一种常见的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。好比,某个服务器的配置信息存在一个文件中,客户端须要经过appConfig的类来读取配置文件的信息。若是有不少地方都须要使用配置文件的内容,也就是说不少地方都须要建立AppConfig对象的示例,这就致使系统中存在多个AppConfig的示例对象,从而严重浪费系统资源。事实上,相似AppConfig这样的类咱们但愿在程序运行期间只存在一个实例对象,这个时候就该考虑使用咱们的单利模式。
场景:
网站的计数器
应用配置
多线程池
数据库配置
数据库链接池
应用程序的日志应用等
Python装饰器是用于拓展原来的函数功能的一种函数,使用Python装饰器的好处就是在不更改原来函数的代码前提下给函数增长新的功能。
装饰器遵循的原则:
对功能的拓展开放
对代码的修改封闭
迭代器是一个抽象的概念,任何对象,若是它的类有 next 方法和 iter 方法返回本身自己,对于 str、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的。
生成器是建立迭代器简单而强大的工具。它们写起来就像是正则的函数,只是在须要返回数据的时候使用yield 语句。每次 next() 被调用时,生成器会返回它脱离的位置。
区别:生成器能够简洁高效的自动建立 iter() 和 next() 方法,它能够完成迭代器的全部事情,使用生成器能够表达式取代列表解析能够节省内存。迭代器在没有后续元素时,next()会抛出一个StopIteration异常。
不可变对象:该对象所指向的内存中的值不能被改变。当改变某个变量是,因为其所指的值不能被改变,至关于把原来的值复制一份后再改变,而且开辟一个新的地址;变量再指向这个新的地址。
可变对象:该对象所指向的内存中的值能够被改变,变量改变后,其实是其所指的值直接发生改变,而且没有复制和开辟新的地址,通俗说就是原地改变。
is 是经过 a 对象和 b 对象的 id 来判断的
== 判断的是 a 对象和 b 对象的值是否相等,经过 value 来判断。
面向对象时至关于面向过程而言,面向过程是一种基于功能分析、以算法为中心的程序设计方法;而面向对象是一种基于结构分析、以数据为中心的程序设计思想。在面向对象语言中有一个重要的东西就是类。
面向对象的三大特性:
封装:
继承:
多态:
match()函数只检测 RE 是否是 string 的开始位置匹配
search()会扫描整个 string 查找匹配
也就是说 match() 只有在 0 位置匹配成功的话才有返回,若是不是开始位置匹配成功的话,match()就会返回 None
- re.findall(r'目的字符串', '原有字符串') # 查询
- re.findall(r'du', 'baidu.com')[0]
- re.sub(r'要替换原字符', '要替换新字符', '原字符串')
- re.sub(r'world', 'python', 'helloworld')
进程:一个运行的程序或者代码就是一个进程,进程是系统资源分配的最小单位,进程拥有本身独立的内存空间,因此进程数据不共享,开销大。
线程:调度执行的最小单位,也叫执行路径,线程不能独立存在,它必须依赖于进程。一个进程中至少有一个线程,也叫主线程。多个线程之间共享内存(数据共享、共享全局变量)从而极大提升了程序的运行效率。
协程:是一种用户态的轻量级线程,协程的调度彻底由用户控制;协程拥有本身的寄存器上下文和栈。
多进程优势:
每一个进程相互独立,不影响主程序的稳定性;子进程崩溃也不要紧。
经过增长CPU,就能够扩充性能
能够尽可能减小线程加锁/解锁的影响,极大提升性能,就算是线程运行的模块算法效率低也不要紧
每一个子进程都有2GB地址空间和相关资源,整体可以达到的性能上限很是大
多进程缺点:
逻辑复杂,须要和主程序交互
须要跨进程边界,不适合大量数据传送;多进程协调开销大
多线程优势:
无需跨进程边界
程序逻辑和控制方式简单
全部线程能够直接共享内存和变量等
线程方式消耗的总资源比进程方式好
多线程缺点:
每一个线程与主程序公用地址空间,受限于2GB地址空间
线程之间的同步和加锁控制比较麻烦
一个线程崩溃可能影响到整个程序的稳定性
达到必定线程数后,即便再增长CPU也没法提升性能
线程可以提升的总性能有限,并且线程多了以后,线程自己的调度也是个麻烦事,须要消耗较多的CPU
能够经过加锁来解决多线程之间的竞争。
加锁的好处:
加锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行
因为能够存在多个锁,不一样的线程持有不一样的锁;并试图获取对象持有的锁时就有可能形成死锁
全局解释器锁(GIL):
全局解释器锁在 Cpython 里才有,它限制了多线程同时执行,同一个进程中只要有一个线程获取了全局解释期(CPU)的使用权,那么其它线程就必须等待该线程的全局解释器(CPU)使用权消失后才能使用全局解释器(CPU)。其实 cpython 中的多线程是伪多线程,因此不少时候使用协程来代替多线程,协程也就至关因而一种更轻量级的线程。
全局解释器锁的优势:
全局解释器锁的缺点:
同步锁:
递归锁(可重入锁)和死锁:
死锁:
递归锁(可重入锁):
每一个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
同一个进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操做,一个线程操做还没有结束,另外一个线程已经对其进行操做,致使最终结果出现错误,此时须要对被操做对象添加互斥锁,保证每一个线程对该对象的操做都获得正确的结果。每一个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
同步:提交完任务后就在原地等待,知道任务运行完毕后,拿到任务的返回值才继续执行下一行代码。如:打电话
异步:提交完任务后不在原地等待,直接执行下一行。如:发短信
阻塞:遇到 I/O 操做时就发生阻塞,程序一旦遇到阻塞操做就会停在原地,而且马上释放CPU资源。
非阻塞(就绪态或运行态):没有遇到 I/O操做,或者经过某种手段让程序即使遇到 I/O 操做也不会停留在原地,执行其余操做,力求尽量多占用CPU。
不管是并行仍是并发,在用户看来都是‘同时’运行的,无论是进程仍是线程都只是一个任务而已;真的干活的仍是CPU,而一个CPU同一个时刻只能执行一个任务。
并发:是伪并行,即看起来是同时运行。
并行:同时运行,只有具有多个CPU的状况下才能实现并行
僵尸进程:一个进程使用 fork 建立子进程,若是子进程退出,而父进程并无调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述任然保留在系统中;这种进程称之为僵尸进程。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程将被 init 进程(进程号为1)所收养,并由 init 进程对它们完成状态收集工做。
避免方案:
fork 两次用孙子进程去完成子进程的任务
用 wait() 函数使父进程阻塞
使用信号量,在 signal handler 中调用 waitpid,这样父进程不用阻塞
解决方案:
SIGCHLD 信号处理:
暴力出奇迹:
查看父进程命令:
ps -ef |grep def 查看僵尸进程 ps -e -o pid,stat |grep Z 查看僵尸进程PID ps -e -o ppid,stat |grep Z 查看僵尸进程的父进程
多进程适合在 CPU 密集型操做(CPU 操做指令比较多,如位数多的浮点运算)。
多线程适合在 IO 密集型操做(读写数据操做较多的好比爬虫)。
线程是并发,进程是并行
进程之间相互独立,是系统分配资源的最小单位,同一个线程中的全部线程共享资源。
并行:同一时刻多个任务同时在运行。
并发:在同一个时间间隔内多个任务都在运行,可是并不会在同一时刻同时运行,存在交替执行的状况。
当程序须要执行较多的读写、请求和回复任务须要大量的 IO 操做时;IO 密集型操做使用并发更好。
CPU 运算量大的程序使用并行会更好。
IO 密集型:在系统运做时大部分的状况下都是CPU在等 I/O(硬盘/内存)的读写。
CPU 密集型:大部分时间用来作计算、逻辑判断等 CPU 动做的程序就称之为CPU密集型。
使用 udp 发送/接收数据不收:
建立客户端套接字
发送/接收数据
关闭套接字
import socket def main(): # 一、建立 udp 套接字 # socket.AF_INET 表示 IPv4 协议,AF_INET6 表示 IPv6 协议 # socket.SOCK_DGRAM 数据报套接字,主要用于 udp 协议 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 二、准备接收方的地址 # 元祖类型 ip 是字符串类型 端口为整型 dest_addr = ('192.168.*.*', 8888) # 要发送的数据 send_data = '我是要发送的数据(#^.^#)' # 三、发送数据 udp_socket.sendto(send_data.encode("utf-8"), dest_addr) # 四、等待接收方发送的数据 若是没有收到数据则会阻塞等待,直到收到数据 # 接收到的数据是一个元组 (接收到的数据, 发送方的 ip 和端口) # 1024 表示本次接收的最大字节数 recv_data, addr = udp_socket.recvfrom(1024) # 五、关闭套接字 udp_socket.close() if __name__ == '__main__': main()
编码的转换
str --> bytes:encode 编码 bytes -->
str:decode() 解码
UDP 绑定端口号:
建立 socket 套接字
绑定端口号
接收/发送数据
关闭套接字
import socket def main(): # 一、建立 udp 套接字 # socket.AF_INET 表示 IPv4 协议 AF_INET6 表示 IPv6 协议 # socket.SOCK_DGRAM 数据报套接字,只要用于 udp 协议 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 二、绑定端口 # 元组类型 ip 通常不写 表示本机的任何的一个 ip local_addr = ('', 7777) udp_socket.bind(local_addr) # 三、准备接收方的地址 # 元组类型 ip 是字符串类型 端口号是整型 dest_addr = ('192.168.*.*', 8888) # 要发送的数据 send_data = "我是要发送的数据" # 四、发送数据 udp_socket.sendto(send_data.encode("utf-8"), dest_addr) # 五、等待接收方发送的数据 若是没有收到数据则会阻塞等待,直到收到数据 # 接收到的数据是一个元组 (接收到的数据, 发送方的 ip 和端口) # 1024 表示本次接收的最大字节数 recv_data, addr = udp_socket.recvfrom(1024) # 六、关闭套接字 udp_socket.close() if __name__ == '__main__': main()
TCP 客户端的建立流程:
建立 TCP 的 socket 套接字
链接服务器
发送数据给服务器端
接收服务器端发送来的消息
关闭套接字
import socket def main(): # 一、建立客户端的 socket # socket.AF_INET 表示 IPv4 协议 AF_INET6 表示 IPv6 协议 # socket.SOCK_STREAM 流式套接字,只要用于 TCP 协议 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 二、构建目标地址 server_ip = input("请输入服务器端的 IP 地址:") server_port = int(input("请输入服务器端的端口号:")) # 三、链接服务器 # 参数:元组类型 ip 是字符串类型 端口号是整型 client_socket.connect((server_ip, server_port)) # 要发送给服务器端的数据 send_data = "我是要发送给服务器端的数据" # 四、发送数据 client_socket.send(send_data.encode("gbk")) # 五、接收服务器端恢复的消息, 没有消息会阻塞 # 1024 表示接收的最大字节数 recv_date= client_socket.recv(1024) print("接收到的数据是:", recv_date.decode('gbk')) # 六、关闭套接字 client_socket.close() if __name__ == '__main__': main()
TCP 服务器的建立流程:
建立 TCP 服务端的 socket
bing 绑定 ip 地址和端口号
listen 使套接字变为被动套接字
accept 取出一个客户端链接,用于服务
recv/send 接收和发送消息
关闭套接字
import socket def main(): # 一、建立 tcp 服务端的 socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 二、绑定 server_socket.bind(('', 8888)) # 三、listen 使套接字变为被动套接字 server_socket.listen(128) # 四、若是有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务 # client_socket 用来为这个客户端服务 # tcp_server_socket 就能够省下来专门等待其余新客户端的连接 client_socket, client_addr = server_socket.accept() # 五、接收客户端发来的消息 recv_data = client_socket.recv(1024) print("接收到客户端%s 的数据:%s" % (str(client_addr), recv_data.decode('gbk'))) # 六、回复数据给客户端 client_socket.send("收到消息".encode('gbk')) # 七、关闭套接字 client_socket.close() server_socket.close() if __name__ == '__main__': main()
注意:
tcp 服务器通常都须要绑定,不然客户端找不到服务器
tcp 客户端通常不绑定,由于是主动连接服务器,因此只要肯定好服务器的 ip、port 等信息就好,本地客户端能够随机
UDP 是面向无链接的通信协议,UDP 数据包括目的端口号和源端口号信息。
优势:速度快、操做简单、占用系统资源少、无需创建链接可实现广播发送。
缺点:因为没有创建链接,并不知道对方是否正确接收数据,不可靠。
TCP 是面向链接的通信协议,须要经过三次握手和四次挥手来完成通信。
优势:传递数据时有确认、窗口、续传、阻塞等控制机制,可以确保数据的正确性,较为可靠。
缺点:相较于 UCP 速度稍慢,占用资源较多。
浏览器发送请求给web服务器
web服务器接收到动态请求后经过wsgi协议调用框架
框架根据请求信息向数据库获取动态数据
框架将获取的动态数据插入模板文件,构成响应体
框架将响应体数据、响应状态码和说明、响应头信息返回给web服务器
web服务器接收到框架提供的数据后将数据按照响应报文的格式编码发送给浏览器
浏览器接收到相应数据后,经过解码并按照http协议格式显示在界面上
先要解析出baidu.com对应的地址
先经过arp获取默认网关(交换机)的mac地址(mac地址指的是物理地址)(UDP广播)
组织数据发送给默认网关(ip是dns服务器的ip,mac是默认网关的mac地址)
默认网关(交换机)拥有转发数据的能力,把数据转发给路由器
路由器根据本身的路由协议,选择一个合适的较快的路径转发数据给目的网关
目的网关(dns服务器所在的网关)把数据转发给dns服务器
dns服务器查询解析出baidu.com对应的IP地址,并将它原路返回给请求这个域名的client
获得了baidu.com对应的ip地址后,会发送tcp三次握手进行链接
使用http协议发送请求数据给web服务器
web服务器收到数据请求以后,经过查询本身的服务器获得相应的结果,原路返回给浏览器
浏览器接收到数据后,经过浏览器本身的渲染功能来显示这个网页
浏览器关闭链接,即四次挥手
传参区别:
GET请求传参会将表单中的信息使用URL拼接的方法显示到浏览器的地址栏中,不安全。
post传参不会暴露信息,安全
GET方法属于URL参数传递信息 以?进行拼接,多个参数使用&形式链接
post会将信息放在请求主体中,这样的信息是不会暴露的。
长度限制:
get传参有长度限制,超过限制后直接报错。60KB
post传参长度不受限制。
缓存:
get方式传递参数浏览器会直接缓存数据,不管多重要的信息浏览器都会缓存。
POST方式浏览不会直接缓存到,比较安全。
特色:
Post:安全
get惟一的好处就是比post快。
cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
cookie 不是很安全,别人能够分析存放在本地的 cookie 并进行 cookie 欺骗考虑到安全应当使用 session。
session 会在必定时间内保存在服务器上。当访问增多,会比较占用服务器的性能考虑到减轻服务器性能方面,应当使用 cookie。
单个 cookie 保存的数据不能超过 4K,不少浏览器都限制一个站点最多保存 20 个 cookie。
建议: 将登录信息等重要信息存放为 SESSION 其余信息若是须要保留,能够放在 cookie 中
经过状态码告诉客户端服务器的执行状态,以判断下一步该执行什么操做。
常见的状态机器码有:
100-199:表示服务器成功接收部分请求,要求客户端继续提交其他请求才能完成整个处理过程。
200-299:表示服务器成功接收请求并已完成处理过程,经常使用 200(OK 请求成功)。
300-399:为完成请求,客户须要进一步细化请求。302(全部请求页面已经临时转移到新的 url)。
30四、307(使用缓存资源)。
400-499:客户端请求有错误,经常使用 404(服务器没法找到被请求页面),403(服务器拒绝访问,权限不够)。
500-599:服务器端出现错误,经常使用 500(请求未完成,服务器遇到不可预知的状况)。
TCP 三次握手流程图
专业版流程:
第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据表发送给Server,Client进入SYN_SENT状态,等待Server确认。
第二次握手:Server收到数据包后由标志位SYN=1知道了Client请求创建链接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认链接请求,Server进入SYN_RCVD状态。
第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,若是正确则将标志位置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,若是正确则链接创建成功,Client和Server进入ESTABLISHED状态,完成三次握手,开始传输数据。
简洁版流程
第一次握手:客户端向服务端发起请求:我想给你通讯,你准备好了么?
第二次握手:服务端收到请求后回应客户端:'ok,你准备好了么。
第三次握手:客户端礼貌的再次回一下客户端:准备就绪,我们开始通讯吧!
补充:SYN-请求询问,ACK-回应
TCP 四次挥手流程图
简洁版流程:
因为 TCP 链接是能够双向通讯的(全双工),所以每一个方向都必须单独进行关闭;客户端和服务端均可以先开始断开链接
四次挥手过程:
第一次挥手:客户端发送带有 fin 标识的报文给服务端,请求通讯关闭
第二次挥手:服务端收到信息后,回复 ACK 答应关闭客户端通讯(链接)请求
第三次挥手:服务端发送带有 fin 标识的报文给客户端,也请求关闭通讯
第四次挥手:客户端回应 ack 给服务端,答应关闭服务端的通讯(链接)请求
第一次握手:客户端先向服务器发出加密通讯的请求,而且提供本身的一些信息(加密方法等),这被叫作ClientHello请求。
第二次握手:服务器收到客户端请求后,向客户端发出回应,而且提供服务器证书、确认的加密方法等,这叫作SeverHello。
第三次握手:客户端收到服务器回应之后,首先验证服务器证书,若是没问题的话会向服务器发送用于加密的随机数、编码改变通知、客户端握手结束通知。
第四次握手:服务器收到客户端的随机数以后,计算生成本次会话所用的"会话密钥",而后向客户端发送编码改变通知和服务器握手结束通知。
三次握手
在创建链接时只须要经过三次握手便可完成。
举个生活中打电话的例子:
小明给小红打电话
小明:去逛街,你准备好了吗?(第一次握手)
小红:嗯,准备好了;你准备好了吗?(第二次握手)
小明:我也准备好了,走吧!(第三次握手)
当双方都准备好的时候就能够去逛街了....
三次握手的好处确保了双方都知道彼此已经准备好
四次挥手
由于 TCP 链接是双向通讯的,所以双方都必须单独进行关闭
第一次挥手:客户端发送带有 fin 标识的报文给服务端,请求通讯关闭
第二次挥手:服务端收到信息后,回复 ACK 答应关闭客户端通讯(链接)请求
第三次挥手:服务端发送带有 fin 标识的报文给客户端,也请求关闭通讯
第四次挥手:客户端回应 ack 给服务端,答应关闭服务端的通讯(链接)请求
注意:客户端收到服务器的确认以后,启动2MSL定时器,在time_wait状态还需再等2MSL(最大报文段生存时间),才会close。防止第四步的确认数据包丢失,万一确认服务器没有收到,服务器再发送FIN时,客户端还能给服务器确认。
主动发送 fin 关闭的一方,在 4 次挥手最后一次要等待一段时间咱们称这段时间为 2MSL。
假定网络是不可靠的,有可能最后一个ACK丢失。因此TIME_WAIT状态就是用来重发可能丢失的ACK报文。若是服务器没有收到ACK,将不断重复发送FIN片断。因此客户端不能当即关闭,要确保服务器接收到该ACK。若是直到2MSL结束客户端都没有再次收到FIN,那么客户端推测ACK已经被成功接收,则关闭TCP链接。
TIME_WAIT 状态的好处:
让四次挥手关闭流程更加可靠
防止丢包后对后续创建的正常链接传输形成破坏
三次握手完成了两个重要的功能,既要双方作好发送数据的准备工做(双方都知道彼此已经准备好),也要容许双方就初始序列化进行协商,这个序列化在握手过程当中被发送和确认。
若是把三次握手改成两次握手,有可能会形成死锁。
举个例子:
客户端和服务端之间的通讯,假定客户端给服务端发送一个创建连接请求分组,服务器收到了这个分组,并发送了答应分组。
按照两次握手的协定,服务器认为链接已经成功创建了,能够开发发送数据分组。但是,客户端在没有收到服务端发送过来答应分组的状况下,客户端将不知道服务端是否已准备好,不知道服务端创建什么样的序列号,客户端甚至怀疑服务端是否收到本身的链接请求分组。在这种状况下,客户端认为链接尚未创建成功,将忽略服务端发来的任何数据分组,只等待链接确认答应分组。而服务端发出的分组超时后,重复发送一样的分组,就这样造成了死锁。
TCP 设有一个保活计时器,客户端若是出现故障,服务器不能一直等下去白白浪费资源。
服务器每收到一次客户端的请求后都会从新复位这个计时器,时间一般设置为2小时,若两小时尚未收到客户端的任何数据,服务器就会发送一个探测报文段,之后每隔75秒钟发送一次,若一连发送10个探测报文任然没有反应,服务器就认为客户端出了故障,接着就关闭链接。
在三次握手过程当中,服务器发送SYN-ACK以后,收到客户端的ACK以前的TCP链接称为半链接(half-open connect).此时服务器处于Syn_RECV状态.当收到ACK后,服务器转入ESTABLISHED状态。
Syn攻击就是 攻击客户端 在短期内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,因为源地址是不存在的,服务器须要不断的重发直 至超时,这些伪造的SYN包将长时间占用未链接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引发网络堵塞甚至系统瘫痪。
Syn攻击是一个典型的DDOS攻击。检测SYN攻击很是的方便,当你在服务器上看到大量的半链接状态时,特别是源IP地址是随机的,基本上能够判定这是一次SYN攻击。
在Linux下能够使用netstat -n -p TCP | grep SYN_RECV1命令检测是否被 Syn攻击。
HTTPS 协议须要到 CA(电子商务认证受权机构) 中心申请证书,通常免费证书较少;须要必定费用。
HTTP 协议是超文本传输协议,使用明文方式传输信息,HTTPS 则是具备安全性的 SSL 加密传输协议。
HTTP 和 HTTPS 使用的是彻底不一样的链接方式,用的端口也不同,前者是 80,后者是 443。
SSL是一种实现网络通讯加密的安全协议,可在客户端(浏览器)和服务器端(网站)之间创建一条加密通道,保证数据在传输过程当中不被窃取或篡改。
SSL证书,也称为服务器SSL证书,是遵照SSL协议的一种数字证书,由全球信任的证书颁发机构(CA)验证服务器身份后颁发。将SSL证书安装在网站服务器上,可实现网站身份验证和数据加密传输双重功能。
HTTP1.1 共有八种请求方式,分别是 GET、POST、PUT、DELETE、HEAD、TRACE、CONNECT。
经常使用的四种请求方式:
GET: 请求指定的页面信息,并返回实体主体。
POST: 向指定资源提交数据进行处理请求,如提交把表单或上传文件;数据被包含在请求体中。
PUT: 从客户端向服务器传送的数据取代指定的文档内容。
DELETE: 请求服务器删除指定的页面。
不经常使用的四种请求方式:
HEAD: 相似于 GET 请求,只不过返回的响应体中没有具体内容,用于获取报头。
CONNECT: HTTP/1.1协议中预留给可以将链接改成管道方式的代理服务器。
OPTIONS: 容许客户端查看服务器的性能。
TRACE: 回显服务器收到的请求,主要用于测试或诊断。
IP: 网络层
TCP/UDP: 传输层
HTTP、RTSP、FTP: 应用层协议
七层模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
URL(Uniform Resource Locator) ,统一资源定位符,可以对因特网的资源进行定位。
URL 通常有四部分组成: <协议> ://< 主机 >:< 端口 >/< 路径 >
如今最经常使用的 <协议> 为 http 协议。
<主机> 是指主机在因特网上的域名。(ip 地址 + 子网掩码 = 主机号)
http 协议的默认 <端口> 为 80(能够省略)。
httpS 协议的默认 <端口> 为 443(能够省略)。
CSS 初始化是指重设浏览器的样式。不一样的浏览器默认的样式可能不尽相同,若是没对 CSS 初始化每每会出现浏览器之间的页面差别。
好处:可以统一标签在各大主流浏览器中的默认样式,使得咱们开发网页内容时更加方便简洁,同时减小 CSS 代码量,节约网页下载时间。
浮动的特征:
浮动元素有左浮动(float:left)和右浮动(float:right)两种。
浮动的元素会向左或向右浮动,碰到父元素边界、其余元素才停下来。相邻浮动的块元素能够并在一行,超出父级宽度就换行。浮动让行内元素或块元素转化为有浮动特性的行内块元素(此时不会有行内块元素间隙问题)。
父元素若是没有设置尺寸(通常是高度不设置),父元素内总体浮动的子元素没法撑开父元素,父元素须要清除浮动。
清除浮动的方法:
父级上增长属性 overflow:hidden。
在最后一个子元素的后面加一个空的 div,给它样式属性 clear:both。
使用成熟的清浮动样式类,clearfix。
clearfix:after,.clearfix:before{ content: "";display: table;}
clearfix:after{ clear:both;}
clearfix{zoom:1;}
什么是Ajax:
Ajax的全称是Asychronous JavaScript And XML(异步JavaScript和XML)
Ajax是一种改善用户体验的技术,利用浏览器内置的ajax对象异步地向服务器发送请求,服务器返回部分数据,浏览器利用这些数据修改页面,整个过程页面无需刷新,不打断用户的请求。
Ajax的优势:
经过异步加载模式,提高了用户体验
优化浏览器和服务器之间的传输,减小没必要要的数据往返,减小了带宽占用
Ajax引擎在客户端运行,承担了一部分原本由服务器承担的工做,从而减小了高并发下的服务器负载
Ajax能够实现动态加载局部刷新
JavaScript脚本语言;
可扩展标记语言 XML;
文档对象模型 DOM;
级联样式表 CSS;
XMLHttpRequest对象。
Django框架:
Django 是一个重量级的框架,Django原生提供了众多的功能组件
Django功能大而全,Django提供了一站式解决的思路,能让开发者不用在开发以前就在选择应用的基础设施上花费大量时间。
Django自带ORM(Object-Relational Mapping 对象关联映射)和模板引擎,支持JinJa等非官方模板引擎,灵活度不高。
Django自带数据库管理app,Django自带的模板引擎简单好用
Django成熟、稳定、开发效率高、相对于Flask,Django的总体封闭性比较好,适合作企业级网站的开发
Django是Python web框架的先驱,用户多,第三方库最丰富,最好的Python库,若是不能直接用到Django中,也必定能找到与之对应的移植
Flask框架:
Flask是一个轻量级web框架,只有一个内核,默认依赖两个外部库:Jinja2 模板引擎和 Werkzeug WSGI 工具集
Flask自由、灵活,可扩展性强,第三方库的选择面广,开发时能够结合本身最喜欢用的轮子,也能结合最流行最强大的Python库
Flask适用于作小型网站以及web服务的API,开发大型网站无压力,不过架构需自行设计
Flask与关系型数据库结合不弱于Django,而与非关系型数据库的结合远远优于Django
Django框架:
主要特色是大而全,集成了不少组件,例如: Models Admin Form 等等, 无论你用获得用不到,反正它全都有,属于全能型框架
优势:
大和全(重量级框架)
自带orm,template,view
须要的功能也能够去找第三方的app
注重高效开发
全自动化的管理后台(只须要使用起ORM,作简单的定义,就能自动生成数据库结构,全功能的管理后台)
session功能
缺点:
template不怎么好用(来自自身的缺点)
数据库用nosql不方便(来自自身的缺点)
若是功能很少,容易臃肿
Tornado框架:
主要特色是原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优点,属于专一型框架
优势:
少而精(轻量级框架)
注重性能优越,速度快
解决高并发(请求处理是基于回调的非阻塞调用)
异步非阻塞
websockets 长链接
内嵌了HTTP服务器
单线程的异步网络程序,默认启动时根据CPU数量运行多个实例;利用CPU多核的优点
自定义模块
缺点:
Flask框架:
主要特色小而轻,原生组件几乎为0, 三方提供的组件请参考Django 很是全面,属于短小精悍型框架
优势:
简单,Flask的路由以及路由函数由修饰器设定,开发人员不须要借助其余文件匹配;
配置灵活,有多种方法配置,不一样环境的配置也很是方便;环境部署简单,Flask运行不须要借助其余任何软件,只须要安装了Python的IDE,在命令行运行便可。只须要在Python中导入相应包便可知足全部需求;
低耦合,Flask能够兼容多种数据库、模板。
缺点:
对于大型网站开发,须要本身设计建构和路由映射规则
因为Flask原生组件少,在版本升级时可能致使某些第三方组件出现问题
Flask-wtf是一个用于表单处理,校验并提供csrf验证的功能的扩展库
Flask-wtf能把正表单免受CSRF <跨站请求伪造> 的攻击
在shell中运行脚本文件
在python编译器中run
会话(seesion)会话数据存储在服务器上。 会话是客户端登陆到服务器并注销的时间间隔。 须要在此会话中进行的数据存储在服务器上的临时目录中。
from flask import session导入会话对象
session['name'] = 'admin'给会话添加变量
session.pop('username', None)删除会话的变量
Flask是一个典型的MVC框架
MVC框架,图形理解
python中的数据库链接有两种方式
在脚本中以用第三方库正常链接,用sql语句正常操做数据库,如mysql关系型数据库的pymsql库
用ORM来进行数据库链接,flask中典型的flask_sqlalchemy,已面向对象的方式进行数据库的链接与操做
WSGI(Web Server Gateway Interface,Web 服务器网关接口)则是Python语言中1所定义的Web服务器和Web应用程序之间或框架之间的通用接口标准。
WSGI就是一座桥梁,桥梁的一端称为服务端或网关端,另外一端称为应用端或者框架端,WSGI的做用就是在协议之间进行转化。WSGI将Web组件分红了三类:Web 服务器(WSGI Server)、Web中间件(WSGI Middleware)与Web应用程序(WSGI Application)。
Web Server接收HTTP请求,封装一系列环境变量,按照WSGI接口标准调用注册的WSGI Application,最后将响应返回给客户端。
Route(路由)
templates(模板)
Models(orm模型)
blueprint(蓝图)
Jinja2模板引擎
蓝图 /Blueprint 是 Flask 应用程序组件化的方法,能够在一个应用内或跨越多个项目共用蓝图。使用蓝图能够极大地简化大型应用的开发难度,也为 Flask 扩展 提供了一种在应用中注册服务的集中式机制。
蓝图的应用场景:
把一个应用分解为一个蓝图的集合。这对大型应用是理想的。一个项目能够实例化一个应用对象,初始化几个扩展,并注册一集合的蓝图。
以 URL 前缀和/或子域名,在应用上注册一个蓝图。 URL 前缀/子域名中的参数即成为这个蓝图下的全部视图函数的共同的视图参数(默认状况下)。
在一个应用中用不一样的 URL 规则屡次注册一个蓝图。
经过蓝图提供模板过滤器、静态文件、模板和其它功能。一个蓝图不必定要实现应用或者视图函数。
初始化一个 Flask 扩展时,在这些状况中注册一个蓝图。
蓝图的缺点:
使用蓝图的三个步骤:
建立一个蓝图对象
```python
blue = Blueprint("blue", name)
```
在这个蓝图对象上进行操做 ,例如注册路由、指定静态文件夹、注册模板过滤器...
```python
@blue.route('/')
def blue_index():
return 'Welcome to my blueprint'
在应用对象上注册这个蓝图对象
```python
app.register_blueprint(blue, url_prefix='/blue')
```
将不一样的功能模块化
构建大型应用
优化项目结构
加强可读性,易于维护(跟Django的view功能类似)
flask_bootstrap
flask_WTF
flask_sqlalchemy
Flask中有三个session:
例如:db.session.add()
from flask_session importSession
from flask import session
SQL优化:
选择最有效的表名排序,对查询进行优化,要尽可能避免全表扫描。
应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描。
最好不要给数据库留NULL,尽量的使用 NOT NULL填充数据库。
应尽可能避免在 where 子句中使用 != 或 <> 操做符,不然将引擎放弃使用索引而进行全表扫描。
数据库结构优化:
范式优化:好比消除冗余等(节省空间)
反范式优化:如适当加冗余等(减小join)
拆分表:垂直拆分和水平拆分
服务器硬件优化:
存储过程就像咱们编程语言中的函数同样,封装了咱们的代码(PLSQL、T-SQL)
存储过程的优势
可以将代码封装起来
保存在数据库之中
让编程语言进行调用
存储过程是一个预编译的代码块,执行效率比较高
一个存储过程替代大量T_SQL语句 ,能够下降网络通讯量,提升通讯速率
存储过程的缺点:
个数据库的存储过程语法几乎都不同,十分难以维护(不通用)
业务逻辑放在数据库上,难以迭代
事务:简单来讲,一个session中进行全部操做,要么同时成功,要么同时失败。
事务的四个基本要素(ACID):
原子性(Atomicity):事务中包含的操做被看作一个逻辑单元,这个逻辑单元中的操做要么所有成功,要么所有失败。
一致性(Consistency):事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程当中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务历来没有执行过同样。
隔离性(Isolation):事务容许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时并行事务的修改必须与其余并行事务的修改相互独立。
持久性(Durability):事务结束后,事务处理的结果必须可以获得固化。
锁:在因此的 DBMS中,锁是实现事务的关键,锁能够保证事务的完整性和并发性。与现实生活中锁同样,它能够使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。固然锁还分级别的。
视图:一种虚拟的表,具备和物理表相同的功能。能够对视图进行增,改,查,操做,试图一般是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得咱们获取数据更容易,相比多表查询。
游标:对查询出来的结果集做为一个单元来有效的处理。游标能够定在该单元中的特定行,从结果集的当前行检索一行或多行。能够对结果集当前行作修改。通常不使用游标,可是须要逐条处理数据的时候,游标显得十分重要。
使用场景:如多个地方须要用到一样的查询结果,该查询结果经常须要编写冗长而复杂的SQL语句...使用视图能够将查询出来的数据进行封装,在使用的时候就变得很是方便。
视图的好处:
重用SQL
简化复杂SQL操做,没必要知道它的实现细节
保护数据,提升安全性
第一范式:字段是最小的单元不可再分。
第二范式:知足第一范式,表中的字段必须彻底依赖于所有主键而非部分主键。
其它字段组成的这行记录和主键表示的是同一个东西,而主键是惟一的,它们只须要依赖于主键,也就成了惟一的。
学号为1024的同窗,姓名为Python3,年龄是23岁。姓名和年龄字段都依赖着学号主键。
第三范式:知足第二范式,非主键外的全部字段必须互不依赖
数据只在一个地方存储,不重复出如今多张表中;能够认为就是消除传递依赖。
好比咱们大学分了不少系(中文系、外语系、计算机系......),这个系别管理表信息有如下字段组成:系编号、系主任、系简介、系架构等。那咱们能不能在学生信息表添加系编号、系主任、系简介、系架构等字段呢???很显然不行,由于这样就冗余了,非主键外的字段造成了依赖关系(依赖到学生信息表),正确的作法是:学生表就增长一个系编号字段。
什么是索引(index):
一种快速查询表中内容的机制,相似于新华字典的目录
运用在表中某些字段上,单存储时,独立于表以外
做用:
索引把数据变成有序的
快速定位到硬盘中的数据文件
索引的优势:
加快数据的检索速度
建立惟一性索引,保证数据库表中每一行数据的惟一性
加速表和表的链接
在使用分组和排序子句进行数据检索时,能够显著减小查询中分组和排序的时间
索引的缺点:
索引须要占物理空间
当对表中的数据进行增长、删除和修改的时候,索引页要动态的维护,下降了数据的维护速度
索引分类:
惟一索引:惟一索引不容许两行具备相同的索引值
主键索引:为表定义一个主键将自动建立主键索引,主键索引是惟一索引的特殊类型。主键索引要求主键中的每一个值是惟一的,而且不能为空
聚焦索引(Clustered):表中各行的物理顺序与键值的逻辑(索引)顺序相同,每一个表只能有一个
非聚焦索引(Non-clustered):非聚焦索引指定表的逻辑顺序。数据存储在一个位置,索引存储在另外一个位子,索引中宝行指向数据存储位置的指针。
确保在多个事务同时存取数据库中的一数据时不破坏事务的隔离性和一致性以及数据库的统一性,乐观锁和悲观锁是并发控制主要采用的技术手段
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做。
在查询完数据的时候就把事务锁起来,直到提交事务
实现方法:使用数据库中的锁机制
缺点:性能低
乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。
在修改数据的时候把事务锁起来,经过version的方式来进行锁定。
实现方法:使用version版本或者时间戳
超键:在关系中能惟一标识元祖的属性集称为关系模型的超键。一个属性能够做为一个超键,多个属性组合在一块儿也能够做为一个超键;超键包含候选键和主键。
候选键(候选码):是最小超键,既没有冗余元素的超键。
主键(主码):数据库表中对存储数据对象予以惟一和完整性标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,既不能为空值(NULL)。
外键:在一个表中存在的另外一个表的主键称此表的外键。
候选码和主码:
例子:邮寄地址(城市、街道名、邮政编码、单位名、收件人)
它有两个候选键:{城市名,街道名}和{街道名,收件人}
若是我选取{城市名,街道名}做为惟一标识实体的属性,那么{城市名,街道名}就是主码{主键}
约束类型: | 主键 | 默认值 | 惟一 | 外键 | 非空 |
---|---|---|---|---|---|
关键字: | PRIMARY KEY | DEFAULT | UNIQUE | FOREIGN KEY | NOT NULL |
总结:
桶排序,是一种复杂度为O(n)的排序
桶排序,是一种稳定的排序
适用于数据均匀分布在一个区间内的场景
pwd 显示工做路径
ls 列出目录中的内容
cd 切换目录
cd /home 进入'/home'的目录
cd .. 返回上一级目录
touch file1 建立一个名为 file1 的文件
mkdir dir1 建立一个名为 dir1 的目录
rm -r file1 删除一个名为 file1 的文件,-f 参数忽略不存在的文件,没有提示。
cp file1 /home 把 file1 文件复制到 /home 目录下
mv 移动目录
cat file1 查看文档或代码
sudo apt-get install 安装命令
netstat -anp | grep service_name
重定向 “>”:
重定向 “>>”:
软链接相似于windows的快捷键,当删除源文件时;软链接也会随之失效。
硬连接能够理解为源文件的一个别名,多个别名所表明的是同一个文件。当 rm 一个文件的时候,那么次文件的硬连接数减 1,当硬连接数为 0 时,文件被删除。
reboot 从新启动操做系统
shutdown -h now 马上关机,其中now至关于时间为 0 的状态
shutdown -h 20:30 系统在今天的 20:30关机
shutdown -h +10 系统过10分钟后自动关机
init 0 关机
init 6 重启
123