多任务
多任务的概念:
至少有3个任务在同时运行,还有很多任务在后台悄悄的运行
多任务的实现有3种方式:
-
多进程模式;
-
多线程模式;
-
多进程+多线程模式
并发:
指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
并行:
指的是任务数小于等于cpu核数,即任务真的是一起执行的。
多线程全局变量是共享的
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据。缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
多线程会出现的问题:
-
如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确
互斥锁
互斥锁为资源引入一个状态:锁定/非锁定
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
# 创建锁 mutex = threading.Lock() # 锁定 mutex.acquire() # 释放 mutex.release()
-
如果这个锁之前是没有上锁的,那么acquire不会堵塞
-
如果在调用acquire对这个锁上锁之前 它已经被 其他线程上了锁,那么此时acquire会堵塞,直到这个锁被解锁为止。
-
和文件操作一样,Lock也可以使用with语句快速的实现打开和关闭操作
import threading import time ticket = 20 lock = threading.Lock() def sell_ticket(): global ticket while True: lock.acquire() if ticket > 0: time.sleep(0.5) ticket -= 1 lock.release() print('{}卖了一张票,还剩{}'.format(threading.current_thread().name, ticket)) else: print('{}票卖完了'.format(threading.current_thread().name)) lock.release() break for i in range(5): t = threading.Thread(target=sell_ticket, name='thread-{}'.format(i + 1)) t.start()
上锁过程:
当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。
每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。
线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。
总结
锁的好处:
-
确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
-
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。
-
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁。
多线程通信
Queue的原理
Queue是一个先进先出(First In First Out)的队列,主进程中创建一个Queue对象,并作为参数传入子进程,两者之间通过put( )放入数据,通过get( )取出数据,执行了get( )函数之后队列中的数据会被同时删除,可以使用multiprocessing模块的Queue实现多进程之间的数据传递。
threading.current_thread() 获取当前正在执行的这段程序的名称
import threading import time from queue import Queue
进程
程序:例如xxx.py这是程序,是一个静态的。
进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程也是可以的。
进程的状态
工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态
新建----就绪----等待----运行-----死亡。
-
就绪态:运行的条件都已经满足,正在等在cpu执行。
-
执行态:cpu正在执行其功能。
-
等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态。
创建进程
multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情。
方法说明
Process( target [, name [, args [, kwargs]]])
-
target:如果传递了函数的引用,可以任务这个子进程就执行这里的代码
-
args:给target指定的函数传递的参数,以元组的方式传递
-
kwargs:给target指定的函数传递命名参数
-
name:给进程设定一个名字,可以不设定
Process创建的实例对象的常用方法:
-
start():启动子进程实例(创建子进程)
-
is_alive():判断进程子进程是否还在活着
-
join([timeout]):是否等待子进程执行结束,或等待多少秒
-
terminate():不管任务是否完成,立即终止子进程
Process创建的实例对象的常用属性:
-
name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
-
pid:当前进程的pid(进程号)
def task(n): print('{}----->start'.format(n)) time.sleep(1) print('{}------>end'.format(n)) if __name__ == '__main__': p = Pool(8) # 创建进程池,并指定线程池的个数,默认是CPU的核数 for i in range(1, 11): # p.apply(task, args=(i,)) # 同步执行任务,一个一个的执行任务,没有并发效果 p.apply_async(task, args=(i,)) # 异步执行任务,可以达到并发效果 p.close() p.join()
功能
-
进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ。
-
线程,能够完成多任务,比如 一个QQ中的多个聊天窗口。
定义的不同
-
进程是系统进行资源分配和调度的一个独立单位.
-
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
区别
-
一个程序至少有一个进程,一个进程至少有一个线程.
-
线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
-
进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
-
线线程不能够独立执行,必须依存在进程中
-
可以将进程理解为工厂中的一条流水线,而其中的线程就是这个流水线上的工人
优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
Queue的使用
-
Queue.qsize():返回当前队列包含的消息数量;
-
Queue.empty():如果队列为空,返回True,反之False ;
-
Queue.full():如果队列满了,返回True,反之False;
-
Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
进程池
from multiprocessing import Pool po = Pool(3) # 定义一个进程池,最大进程数3 for i in range(0,10): # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,)) # 每次循环将会用空闲出来的子进程去调用目标 po.apply_async(worker,(i,))
multiprocessing.Pool常用函数解析:
-
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
-
close():关闭Pool,使其不再接受新的任务;
-
terminate():不管任务是否完成,立即终止;
-
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
简单总结
-
进程是资源分配的单位
-
线程是操作系统调度的单位
-
进程切换需要的资源很最大,效率很低
-
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
-
协程切换任务资源很小,效率高
-
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
网络通讯
ip地址
ip地址的作用:在互联网通信中,我们使用IP地址来查询到各个主机。
用来标记网络上的一台电脑 。同一个局域中不允许重复
dos 命令 ipconfig (查看IP地址)
什么是socket?
-
socket是来完成网络通信必备的东西。
-
socket(简称
套接字
) 是进程间通信的一种方式。 -
它与其他进程间通信的一个主要不同是
-
它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的。
-
例如我们每天浏览网页、QQ 聊天、收发 email 等等
UDP协议
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议。
在通信开始之前,不需要建立相关的链接,只需要发送数据即可,类似于生活中,"写信"。
UDP的特点 :
类似于一个写信的模型,数据有可能会丢失。
相对于TCP创建要简单的多。
TCP协议
TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)
是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。(比较稳定的信息传输)
TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,"打电话"
TCP特点
面向连接:
通信双方必须先建立连接才能进行数据的传输。
数据传输前医药建立连接
双方都必须为该连接分配必要的系统内核资源,管理连
接的状态和连接上的传输。(稳定传输)
可靠传输: 超时重传,错误效验, 流量控制和阻塞管理
TCP与UDP的区别
信息传输:
-
TCP 面向连接(确认有创建三方交握,连接已创建才作传输。)
传输数据中 传递方成功收到数据后会给传递方回应收到数据了。
没有收到数据会 :信息重传 、重发丢失的数据包 、舍弃重复的数据包
、无差错的数据传输、阻塞/流量控制。保证了信息传递的可靠性。
-
UDP 可以直接发送数据 ,数据容易丢失 ,传输数据中 是否成功传递消息 是不会回应对方的。
-
最终保证了 TCP 比 UTP稳定 直到现在 TCP也是长应用的。UTP一般不常用。
TCP 服务端创建流程:
-
socket 创建套接字
-
建立一个地址 ip+端口
-
bind绑定 ip +port
-
listen 始套接字变为被动
-
sccpept 阻塞 等待客户连接
-
recv 、send 接受 发送
-
关闭套接字
TCP 文件下载案例
TCP服务器端:
from socket import * def get_dile_context(file_name): """ 打开文件功能""" try: # 追加打开文件,二进制只读模式 f = open(file_name, 'rb') countent = f.read(1024) # 读取文件 while countent: # 定义生成器 循环读取 yield countent # 读取文件 直达读取结束 countent = f.read(1024) except: # 异常处理 print(f'数据{file_name}不存在') return None def run_server(): ''' tcp 发送文件 ''' # 1.创建套接字 server = socket(AF_INET,SOCK_STREAM) # 2.绑定端口 必须是元组类型 server.bind(('', 6789)) # 3.监听 server.listen(128) """ 4.阻塞程序 将程序停留在这个一行等待客户端激活 accept() 有返值是一个元组 (创新的调套接字,客户端的地址和端口) client== 客户端的连接相当于新的个管道 == 拨打10086 提供的客服 (又多打电话 就有对少客服) 新产生的套接字 用来为客户服务 当收到客户端发来的消息就会被唤醒 """ #adder 客户端的地址和端口 client, addr = server.accept() print('访问客户端的地址为:', addr) # 接受用户端传递的消息 , 获取用户端的信息转码 file_name =client.recv(1024).decode('utf-8') # 调用功能函数 打开文件 gr = get_dile_context(file_name) # 循环发送 for data in gr: client.send(data) print('服务端:',len(data)) # 关闭 client.close() server.close() if __name__ == '__main__': # 调用 run_server()
TCP客户端:
# 导入模块 from socket import * # 创建套接字 ip v4 tcp client = socket(AF_INET, SOCK_STREAM) # 连接信息 ip地址 +端口 addr = ('localhost',6789) # tcp 通信三次握手机会 client.connect(addr) # 元组 # 下载文件 file_name = input("请输入要下载的文件名:") # 转码 发送 client.send(file_name.encode("utf-8")) # 接受文件 date = client.recv(1024) # 循环接受 while date: # 新建文件 字符串拼接 二进制写入追加 with open('[新]'+file_name,'ab') as f: f.write(date) # 再次执行打开 直到循环结束 date = client.recv(1024) # 打印了一个传输状态 print('客户端:',len(date)) # 提示结束了 print('结束了')
Day 8 HTTP 协议
Linux系统
命令:
查看文件下所有目录:dir
Day 1 操作系统
计算机由硬件和软件两大部分组成,软件部分里又被分为系统软件和应用软件,而在系统软件里,又有一个操作系统。
没有安装操作系统的计算机,通常被称为 裸机
如果想在 裸机 上运行自己所编写的程序,就必须用机器语言书写程序
## 什么是操作系统
> 是现代计算机系统中 最基本和最重要 的系统软件 > > 是 配置在计算机硬件上的第一层软件,是对硬件系统的首次扩展 > > 主要作用是管理好硬件设备,并为用户和应用程序提供一个简单的接口,以便于使用 > > 而其他的诸如编译程序、数据库管理系统,以及大量的应用软件,都直接依赖于操作系统的支持
### 操作系统分类
> 桌面操作系统 > > 服务器操作系统 > > 嵌入式操作系统 > > 移动设备操作系统
### 桌面操作系统
- Windows 系列 - 用户群体大 - macOS - Linux - 应用软件少
### 服务器操作系统
- Linux
- 安全、稳定、免费 - 占有率高
- Windows Server
- 付费
- 占有率低
### 嵌入式操作系统
- Linux
### 移动设备操作系统
- Android、iOS、Symbian、WindowsMobile、BlackBerry
## Linux系统介绍
Linux是一套免费使用和自由传播的类Unix操作系统,基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统,继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。
主要特征 :基本思想、 完全免费 、完全兼容POSIX1.0标准、多用户,多任务 、良好的界面 、支持多种平台
## Linux启动流程(了解)
启动加载BIOS:BIOS是系统启动时加载的第一个软件。
开机自检
对外部设备进行初始化,读取BIOS参数
查找MBR(Master Boot Record,主引导分区)。如果未找到,会提示找不到硬盘。
读取主引导分区(MBR)
启动引导代码(bootloader
加载内核,进入操作系统 :运行第一个程序 : /sbin/ini。
sbin/init 会读取相关的配置文件,来确定系统的运行级别。
根据对应的运行级别,查找对应的脚本文件。
## 远程连接Linuxpw
在实际开发中,Linux服务器都是被放在服务器机房里的,不能直接进入到服务器机房去操作这台Linux服务器,而是通过一些远程链接工具,对Linux服务器进行管理。
## SSH协议
SSH 为 Secure Shell的缩写,由 IETF 的网络小组(Network Working Group)所制定;
SSH 为建立在应用层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。
Ubuntu默认没有安装ssh服务,需要我们使用代码手动的在Ubuntu服务器上安装ssh服务。
## 软件安装相关指令
在Linux中,很多功能需要使用命令行来实现,我们甚至可以不使用桌面,只使用终端命令在Linux里实现绝大多数功能。
令的基本格式:
```python 命令: [选项] [参数] 例如: ls -a # 表示列出根目录下所有的文件及文件夹 (先进入根目录) ```
Linux系统可以分为Debian和RedHat两大分支。基于Debian平台比较流行的操作系统是Ubuntu,基于RedHat平台比较流行的操作系统是fedora.两种不同的分支,它们所使用的软件管理命令也是不一样的。
基于Debian平台的操作系统,使用dpkg和apt指令管理软件,基于RedHat平台的操作系统,使用rpm和yum指令来管理软件。它们的命名方式不同,但是命令的执行效果大致相同,基于Fedora平台CentOS系统下的rpm和yum指令。
## 软件管理相关指令
简单来说,Linux系统可以分为Debian和RedHat两大分支。基于Debian平台比较流行的操作系统是Ubuntu,基于RedHat平台比较流行的操作系统是fedora.两种不同的分支,它们所使用的软件管理命令也是不一样的。
基于Debian平台的操作系统,使用dpkg和apt指令管理软件,基于RedHat平台的操作系统,使用rpm和yum指令来管理软件。它们的命名方式不同,但是命令的执行效果大致相同,我们主要学习基于Fedora平台CentOS系统下的rpm和yum指令。
### rpm(了解)
rpm是“Red-Hat Package Manager”的简写,为 Red Hat专门开发的套件管理系统,方便软件的安装、更新及移除。所有源自Red Hat的“Linux ”发行版都可以使用 rpm.
命令行 | 作用 | 示例 |
---|---|---|
rpm -ivh <.rpm file name> | 安装.rpm后缀名的软件,并显示安装详情 | rpm -ivh google-chrome-stable_current_x86_64.rpm |
rpm -e <packagename> | 删除指定的软件 | rpm -r google-chrome-stable |
rpm -qa | 列出电脑上安装的所有包 | rpm -qa |
### yum
yum(全称为 Yellow dog Updater, Modified)
是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。
基于RPM包管理,能够从指定的服务器自动下载RPM包并且安装。
可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次 下载、安装。
命令行 | 作用 | 示例 |
---|---|---|
yum search <packagename> | 搜索软件包 | yum search python |
yum list installed | 列出已经安装的软件包 | yum list installed |
yum install <packagename> | 用来安装指定的软件包 | yum install vim |
yum remove | 用来移除软件包 | yum remove vim |
yum update <packagename> | 更新软件包 | yum updat tar |
yum check-update | 检查更新 | yum check-update |
yum info <packagename> | 列出指定软件包详情 | yum info python |
### 区别
yum是基于rpm的,它的功能更加强大。
场景 | rpm | yum |
---|---|---|
离线的.rpm安装包 | 能够安装,但是不能自动下载安装依赖 | 能够安装,并且能够自动安装下载安装依赖 |
在线安装 | 不支持,只能把安装包下载到本地安装 | 支持在线下载安装 |
## 文件系统
### Linux里的文件系统
管理和存储文件信息的软件机构称为文件管理系统,简称文件系统
系统就是负责为用户建立、读取、修改和转储文件,控制文件的存取,当用户不 再使用时撤销文件等。
常见的文件系统介绍:
FAT16 :每个磁盘的分区最大只能达到2G,并且会浪费很多空间。
缺点:无法存放大于4GB的单个文件,而且容易产生磁盘碎片,性能不佳。
FAT32:Windows95以后的系统都支持。
在一个不超过8GB 的分区中FAT32分区格式的每个簇容量都固定为4KB,减少磁盘的浪费。
FAT不支持长文件名,只能支持8个字符,且后缀名最多只支持3个字符。
且后缀名最多只支持3个字符。
NTFS:WindowsNT系列设计,用来取代FAT系统。簇的空间更小,磁盘的利用率更 高,并且可以共享资源、文件夹以及对文件设置访问许可权限。
RAW:RAW文件系统是一种磁盘未经处理或者未格式化产生的文件系统
没有格式化、格式化中途取消、硬盘出现坏道、硬盘出现不可预知的错误
EXT:EXT是扩展文件系统,目前最新的版本是5.0.
HFS(+):苹果电脑上的文件系统。
## Linux里的文件系统
Linux里只有一个盘符,是从 " / " 开始的,只有它是没有上级目录的。
目录系统像树形结构," / " 相当于树形结构的根,将 " / " 称之为根目录。
/ -- 系统的根目录(最顶级目录)
/bin -- 二进制文件,可执行文件。我们在命令行里执行的指令,如 ls,rm,cp,mv。
/boot -- 系统启动相关时所需的文件。(勿动)
/dev -- 设备文件,将新的网络摄像头连接到机器中,自动弹出一个新的设备条目。
/etc -- 用来存放所有的系统管理所需要的配置文件和子目录。
/home-- 用户的主目录,用户都有自己的目录,所有的用户都存放在home目录下。
(不是超级管理员 家都是在home里)
/lib(64) -- 用来存放系统最基本的动态连接共享库,几乎所有的应用程序。
/lost+found -- 目录一般情是空的,系统非法关机,会存放些没来得及保存的文件。
/mnt -- 该目录是为了让用户临时挂载别的文件系统的,可以将光盘挂载在/mnt/上
/opt -- 给额外安装软件摆放的目录。比如安装ORACLE数据库可以放到这个目录下
/proc -- 虚拟目录,它是系统内存的映射,可以通过直接访问这个目录取系统信息。
/root -- 超级用户目录。
/sbin -- 超级用户使用的命令存放目录。
/srv -- 存放一些服务启动之后需要提取的数据。
/sys -- 映射内核设备。
/tmp -- 存放临时文件。
/usr -- 非常重要的目录,用来存放用户安装的应用程序和用户文件。
/var -- 经常修改的数据,比如程序运行的日志文件
以 " . " 开头的文件是隐藏文件。
" ./ " 表示的是当前目录; “ ../ ” 表示的上级目录
“ ~ ” 表示的当前用户的家目录
## 目录操作的常见指令
pwd:查看当前工作目录
cd:切换工作目录
符~号 | |
---|---|
. | 当前目录 |
.. | 上一级目录 |
~ | 当前用户的家目录 |
- | 表示上次切换之前的目录 |
/ | 表示根目录 |
> 1.使用cd时,不指定目标地址,会切换到家目录 > > 2.凡是以/开头的目录都是绝对目录 > > 3.凡是以.或..开头的目录都是相当目录
### ll:查指定目录内容,不指定目录时查看当前工作目录
选项 | 说明 |
---|---|
ll -a | 显示所有文件,包括隐藏文件 ,ll 空格 -a |
ll -l | 列表显示,详细信息 |
ll -h | 人性化的显示大小,如:K/M/G |
-l选项显示的结果:类型及权限 | 连接数 | 用户 | 用户组 | 大小 | 月 | 日| 年/时间 | 名称
文件类型:(-l显示结果中的第一部分的第一列)
连接数:如果是文件,表示这个文件有多少个名字(硬链接);如果是目录,表示这个目录里有多少个子目录。
符号 | 类型 |
---|---|
- | 普通文件。包括纯文本文件(ASCII);二进制文件(binary);数据格式的文件(data);各种压缩文件等。 |
d | 目录文件。 |
l | 链接文件。类似于Windows里的快捷方式。 |
c | 字符设备文件。即串行端口的接口设备,例如键盘、鼠标等等。 |
b | 块设备文件。就是存储数据以供系统存取的接口设备,简单而言就是硬盘 |
s | 套接字文件。这类文件通常用在网络数据连接,最常在 /var/run目录中看到这种文件类型。 |
p | 管道文件。它主要的目的是,解决多个程序同时存取一个文件所造成的错误。 |
- alias:给命令起别名。
```shell alias md=mkdir Copy ```
相当于给mkdir命令起了一个别名,以后使用md即可创建一个文件夹。
```shell alias # 不添加任何参数,表示列出所有的别名 ```
## 常用文件命令
cd ~ -- 自己家(root用户)
ssh - 公网ip -- 进入(60.205.218.255)(Yjz1314520!)
exit -- 退出
pwd --当前所在目录的位置
ll -- 当前用户下得所有文件
ls -- 简介显示有文件
cd / -- 跳转到顶级目录
./ -- 同一级别
../ -- 上一级别
ctrl + l -- 快捷键清楚屏幕
ls -a / # 表示列出根目录下所有的文件及文件夹(隐藏显示)
python3 -- 打开python
python - v -- 查看是否安装python
su 用户名-- 切换用户 (root 转用户)
whereis -- 查看文件路径 (whereis python --python在哪里 )
act -- 查看有什么
su - 用户名 -- 切换用户
ctrl -c -- 查看时直接退出
## 文件和目录的创建删除
命令 | 说明 |
---|---|
touch | 新建文件,可以是多个 # touch i.py b,py |
rm | 删除文件或目录(删除目录时要传递'-r'选项) |
cp | 拷贝文件或目录(拷贝目录是要传递'-r'选项) |
mv | 相关命令移动文件或目录 |
mkdir | 命令创建目录,可以是多个 |
rmdir | 删除空目录 |
创建多个 或 删除多个用空格隔开 。
复制 移动 要在末尾添加路径。
选项说明
- -r:删除或拷贝目录时需要添加,表示递归操作。
- -f:表示强制操作,没有提示信息。
- *
:表示模糊匹配,如:rm* .py
,表示删除所有的py文件。
- -p:创建目录时若需要创建中间目录,可以添加此选项。
```python mkdir -p a/b/c # a文件夹中由b b文件夹中由c (递增去创建) 命令 -rf 文件名 -- 之间删除文件夹(没有任何询问) ```
## 查看文件
命令 | 说明 |
---|---|
cat | 从上到下,显示文件全部内容 |
tac | 从下到上,显示文件全部内容 |
head | 查看开头指定行数的内容,不指定时默认10行,如:head - 20 filename |
tail | 查看文件末尾指定行数的内容,不指定时默认10行,如:tail - 5 filename |
nl | 功能与cat相同,但是多显示了行号 |
wc | 统计显示,内容:行数 单词数 字符数 文件名 |
more | 一点一点查看内容 |
less | 一点一点查看内容 |
- more/less使用说明 - 显示一屏就停止 - q退出查看 - enter下翻一行 - 空格下翻一屏 - more查看完毕会自动退出,less不会 - less可以使用上下按钮上下翻看,more不可以 - 经常结合管道使用:ls /etc | more - ctrl -c -- 直接退出
## 用户管理相关命令
### 用户管理
命令 | 说明 |
---|---|
whoami | 查看当前登录的用户名 |
useradd | 新建用户,-d指定家目录,-m创建家目录,-s指定shell |
userdel | 删除用户,-r会删除用户家目录 |
passwd | 设置指定用户的密码,没有指定用户,是修改当前用户的密码 |
su - | 切换用户,一定要加上'-',否则只会切换家目录,但是环境没有切换,不指定用户时默认切换到root用户(记得先给root用户设置密码) (切换直接退出 exit()) |
sudo | 以指定用户(root)身份执行命令。 |
visudo | 专门用于编辑/etc/sudoers文件的命令,需要将指定用户添加进去才可以使用sudo命令,如:test ALL=(ALL:ALL) ALL;使用sudo update-alternatives --config editor可以修改系统默认编辑器(nano) |
groupadd | 新建用户组 |
groupdel | 删除用户组 |
gpasswd | 向指定组添加/删除指定的用户,如:gpasswd -a/-d user group |
groups | 查看指定用户的组信息 |
chsh | 修改指定用户的shell解析器,如:sudo chsh test -s /usr/sbin/nologin (禁止登陆) |
chown | 修改文件所属用户[及用户组],如: sudo chown test[:test] 1.py,递归操作需要加'-R'选项 用户名:组名 文件路径(可以是就对路径也可以是相对路径) 1.chown -R xiaomi:xiaomi /temp/temp1 (文件夹递修改) 2.sudo chown liuxin:liuxin 理想人生.txt |
chgrp | 修改文件所属用户组,如:sudo chgrp test 1.py |
删除用还后 可以用 su - 查看 (用户是否存在) 在把相对应的用户文件夹删除
## vim编辑器
### vim的使用
Vim是类似于Vi的著名的功能强大、高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性(编写,修改文件的作用)
### 安装
``` sudo yum install vim ```
### 使用
vim 有三种工作模式:命令模式,输入模式,编辑模式。
!v : 打开最后使用vim打开的文件
vim filename : 打开/新建一个文件
vim 文件名称.格式(i编辑模式直接填写)
进入以后不做编辑填写退出以后 ,就不会显示在目录当中。
命令模式:按Esc键切换到命令模式
命令/操作 | 说明 |
---|---|
ZZ(shift + zz) | 保存退出 |
光标定位 | |
vim filename +n | 打开文件,将光标定位到第n行 |
vim filename + | 打开文件,将光标定位到最后一行 |
gg | 定位到首行 |
G | 定位到尾行 |
ngg | 定位到第n行 |
^/0 | 定位到行首 |
$ | 定位到行尾 |
k | ↑ |
j | ↓ |
h | ← |
l | → |
ctrl + f | 下翻一页 |
ctrl + b | 上翻一页 |
ctrl + d | 下翻半页 |
ctrl + u | 上翻半页 |
内容处理 | |
x | 向右删除一个字符 |
nx | 向右删除n个字符,n表示个数 |
X | 向左删除一个字符 |
nX | 向左删除n个字符,n表示个数 |
dd | 删除光标所在行 |
ndd | 删除光标开始的n行 |
p | 粘贴剪切板中的内容 |
yy | 复制光标所在行 |
nyy | 复制光标开始的n行 |
u: | 撤销 |
ctrl + r | 反撤销 |
编辑模式:在命令模式下,按 : 键进入到编辑模式。
命令 | 说明 |
---|---|
:w | 保存 |
:q | 退出 |
:wq | 保存退出 |
:x | 保存退出 |
:w! | 强制保存 |
:q! | 强制退出,不保存修改 |
:e! | 放弃修改,恢复到修改之前的状态 |
:w newfile | 文件另存为 |
:set nu[mber] | 显示行号 |
:set nonu[mber] | 隐藏行号 |
:set tabstop=4 | 设置一个tab缩进4个字符 |
:set mouse=a | 启用鼠标的点击功能 |
[:]/内容 | 查找指定内容,n下翻,N上翻 |
[:]?内容 | 查找指定内容,N下翻,n上翻 |
:%s/原内容/新内容/[g] | 所有行内容替换,g表示全局(默认只能替换一行中第一处) |
:m,ns/原内容/新内容/[g] | m到n行内容替换,g用法同上 |
光标定位 | |
:n | 将光标定位到第n行,n表示行号 |
输入模式:
命令 | 说明 |
---|---|
i | 在光标位置插入 |
I | 在第一个非空字符插入 |
a | 在光标的下一个字符输入 |
A | 在行尾插入 |
o | 在光标所在的行下面插入空行 |
O | 在光标所在的行上面插入空行 |
s | 删除光标所在字符,并进入输入模式 |
S | 删除光标所在行,并进入输入模式 |
## 权限管理
说明:在linux下,所有的文件都涉及权限,分为三组:所有者、所属组、其他
权限:所有文件的权限可以分为:可读(r)、可写(w)、可执行(x),'-'表示没有改权限
原理:ls -l的结果,三位一组,分为三组,刚好对应:所有者、所属组、其他
修改权限:chmod,格式:chmod [身份] [操作] [权限] 文件
选项 | 说明 |
---|---|
身份 | |
u | 所有者(user) |
g | 所属组(group) |
o | 其他(other) |
a | 所有(all) |
操作 | |
+ | 添加 |
- | 去掉 |
= | 设置 |
权限 | |
r | 可读 |
w | 可写 |
x | 可执行 |
> sudo chmod o+w 1.py,给其他用户添加可写的权限(可以随意更改)
- 本质:使用一组(3位)八进制的数据来表示权限,如:0755,展开如下:
``` 转换为二进制:0755 => 111 101 101 对应三组身份: 所有者 所属组 其他 每一组的权限:都包括 可读、可写、可执行 示例解析:所有者可读可写可执行,所属组可读可执行,其他可读可执行 Copy ```
- 简化操作:sudo chmod 0755 1.py
> 若要进行递归操作,则需要添加'-R'操作
- umask
``` 作用:用来限定新建文件的默认权限,权限与该值相反。 命令:umask [value],查看或设置掩码 分析: 掩码:0002 => 000 000 010 新建目录: 111 111 101 新建文件: 110 110 100 ```
## 压缩解压命令
tar,打包解包工具,后缀名是tar.
```bash # 解压方法与 压缩方法 都是相对应的 () 选项: -c:创建新的打包文件 -x: 解包。 -t: 不解包查看文件。 注意:以上三个选项不能同时使用,因为功能冲突。 -v: 显示详细信息。 -f: 指定操作文件。 -z: 调用gzip/gunzip进行压缩解压操作,后缀名是.tar.gz -j: 调用bzip2/bunzip2进行压缩解压操作,后缀名是.tar.bz2 示例: tar -cvf test.tar test # 将test文件夹打包成test.jar文件,并显示打包信息 tar -cvf 123.tar 1.txt 2.txt 3.txt # 将1.txt,2.txt和3.txt文件打包到123.tar文件 tar -tf 123.tar # 不解包查看123.tar文件里的内容 tar -xvf 123.tar # 解包123.tar文件,并显示详细信息
tar -zcvf 12.tar.gz 1.txt 2.txt # 将1.txt和2.txt压缩并打包成12.tar.gz文件 tar -jcvf 12.tar.bz2 1.txt 2.txt # 将1.txt和2.txt压缩并打包成12.tar.bz2文件
tar -zxvf 12.tar.gz # 解压并解包12.tar.gz文件 tar -jxvf 12.tar.bz2 # 解压并解包12.tar.bz2文件。 ```
注意:tar 只是用来打包和解包的工具,它本身是没有压缩和解压缩的功能。但是,通过添加参数,可以调用gzip或者bzip2进行压缩解压操作。
- tar -z: 使用 gzip方式打包并压缩文件,后缀名为 .tar.gz,可以简写为 .tgz
- tar -j: 使用 bzip2 方式打包并压缩文件,后缀名为 .tar.bzip2,可以简写为 .tbz2 或 .tbz
解压 -z xvf (没有顺序) -c e/ -c 表示复制
## Nginx的安装和配置
Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器。
Nginx可以作为反向代理进行负载均衡的实现。 (分化压力)
\1. 使用wget
命令下载Nginx源码,下载地址: http://nginx.org/download/nginx-1.16.0.tar.gz \2. 解压软件压缩包: tar -zxvf nginx-1.16.0.tar.gz
\3. 编译前执行配置文件: ./configure
- —prefix:用来配置Nginx服务器的安装目录 - 配置出错多数是因为缺少相关的依赖库或者编译器 - 需要安装相关的依赖。sudo yum install gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel
- 运行 make && make install
命令来编译并安装软件 \4. Nginx介绍 - 进入到/usr/local/nginx/sbin
安装目录,使用 ./nginx
命令启动nginx - html:默认站点目录 - 测试:在浏览器中输入localhost,看到welcome to nginx即表示成功
正向代理 : 客户端的改变
反向代理:为服务端做的 客户端无感 (nginx (的过程为:负载均衡))
## 管理虚拟环境
Python对包和模块的下载、存储以及管理有其自己的一套方法。Python的包一般存在几个地方,使用sys.path
可以查看python包和模块的存放路径。
### 安装virtualenv
virtualenv 是一个创建隔绝的Python环境的工具。virtualenv创建一个包含所有必要的可执行文件的文件夹,用来使用Python工程所需的包。
```shell udo pip install virtualenv Copy ```
安装完成以后,可以使用命令快速的创建、激活虚拟环境。
```shell cd my_project # 进入到工程的工作目录 virtualenv test # 创建虚拟环境,并命名为test.此时会在my_project下多出一个test的文件夹 source test/bin/activate # 激活虚拟环境。此时,如果使用pip install安装的插件,都会被安装到当前虚拟环境 pip install flask # 测试安装flask. flask会被安装到当前虚拟环境,而不是全局环境 ```
管理虚拟环境
```shell mkvirtualenv test # 创建并切换到test虚拟环境 deactivate # 离开test虚拟环境 rmvirtualenv test # 删除test虚拟环境 workon demo # 切换到demo虚拟环境 ```
## 服务监听
- 参数:
```shell -a 显示所有socket,包括正在监听的。 -n 以网络IP地址代替名称,显示出网络连接情形。 -o 显示与与网络计时器相关的信息 -t 显示TCP协议的连接情况 -u 显示UDP协议的连接情况 -p 显示建立相关连接的程序名和PID。 Copy ```
- ps
- 作用:查看进程信息 - 使用: - ps -ef - ps aux - 说明:经常在查询进程号的时候结合grep进行过滤
- pstree
- 作用:使用树形结构查看进程信息。
- kill
- 作用:杀死进程
- 示例:kill -9 PID
- 说明:强制杀死指定进程
ps -ef | grep 80 -- 结合使用进行过滤
## 管道
管道的操作符是 " | ",它只能处理经由前面一个指令传出的正确输出信息。
然后传递给下一个命令,作为下一个命令的标准输入。
例如ps -ef|more
(后面必须是可视化) (一点一点读取)cd 直接跳出
注意:
- 管道命令只能处理前一个命令的正确输出,不能处理错误输出。 - 管道命令的右边命令,必须要能够接收标准的输入流才行。
有些命令无法接受输入流,需要通过xargs来将输入流转换成为命令行参数。
如:find -name 2.txt | xargs rm -rf
## 重定向
标准输入(stdin)、标准输出(stdout)、标准错误(stderr)
- 在linux中,创建任意进程,系统会自动创建上面三个数据流,其实就是三个文件
- 三个文件的描述符分别是:0、1、2.其中,0默认指向键盘,1和2默认指向终端窗口。
- 重定向就是改变原来默认的表现位置。
- 演示:
``` 输出重定向: ls > 1.txt # 会新建文件,若文件已存在,会清空 ls >> 1.txt # 追加到文件末尾,若文件不存在则创建 错误重定向: ls /xxx 2> 1.txt # 将标准错误重定向到1.txt 同时重定向输出和错误: ls /xxx /home &> 1.txt # 将标准输出和错误同时重定向到1.txt文件 ```
WEB搭建服务器
简单的:
import socket def handle_client(client_scoket): # '为客户端进行服务' # '接受客户端的请求内容消息后进行转码' recv_data = client_scoket.recv(1024).decode('utf-8') print(recv_data) # 通过换行符进行切割: request_header_lines = recv_data.splitlines() # 打印出来 for line in request_header_lines: print(line) # 响应头信息 response_headers = 'HTTP/1.1 200 OK\r\n' # 响应头 编码类型 response_headers += 'content-type:text/html; charset=utf-8\r\n' # 用一个空行 和响应体 分隔开 response_headers += '\r\n' # 相应体 内容 response_body = 'hello,你好世界' response = response_headers + response_body client_scoket.send(response.encode('utf-8')) client_scoket.close() def main(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('', 7788)) server_socket.listen(128) while True: client_socket, client_addr = server_socket.accept() handle_client(client_socket) if __name__ == '__main__': main()
搭建需要的静态页面
import socket import re def handle_client(client_scoket): # '为客户端进行服务' # '接受客户端的请求内容消息后进行转码' recv_data = client_scoket.recv(1024).decode('utf-8', errors='ignore') print(recv_data) # 通过换行符进行切割: request_header_lines = recv_data.splitlines() # 打印出来 for line in request_header_lines: print(line) # 获取请求行 也就是列表中下表为0的元素 http_request_line = request_header_lines[0] # 提取请求行中的路径 get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1) print("file name is ===>%s" % get_file_name) # 如果没有指定访问哪个页面。例如index.html if get_file_name == '/': get_file_name = DOCUMENTS_ROOT + "/index.html" else: get_file_name = DOCUMENTS_ROOT + get_file_name print("file name is ===2>%s" % get_file_name) # for test try: f = open(get_file_name, "rb") except IOError: # 404表示没有这个页面 response_headers = "HTTP/1.1 404 not found\r\n" response_headers += "\r\n" response_body = "====sorry ,file not found====".encode('utf-8') else: # 响应头信息 response_headers = 'HTTP/1.1 200 OK\r\n' # 用一个空行 和响应体 分隔开 response_headers += '\r\n' # 相应体 内容 response_body = f.read() f.close() finally: # 因为头信息在组织的时候,是按照字符串组织的,不能与以二进制打开文件读取的数据合并,因此分开发送 # 先发送response的头信息 client_scoket.send(response_headers.encode('utf-8')) # 在发生响应体 client_scoket.send(response_body) client_scoket.close() def main(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('', 7788)) server_socket.listen(128) while True: client_socket, client_addr = server_socket.accept() handle_client(client_socket) # 静态资源的目录 DOCUMENTS_ROOT = './blog_ye' if __name__ == '__main__': main()
多进程WEB服务器
import socket import re import multiprocessing class WSGIServer(object): def __init__(self,server_address): # 创建一个tcp套接字 self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 允许立即使用上次绑定的port self.listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定 self.listen_socket.bind(server_address) # 变为被动,并制定队列的长度 self.listen_socket.listen(128) def serve_forever(self): "循环运行web服务器,等待客户端的链接并为客户端服务" while True: # 等待新客户端到来 client_socket, client_address = self.listen_socket.accept() print(client_address) # for test new_process = multiprocessing.Process(target=self.handleRequest, args=(client_socket,)) new_process.start() # 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的 client_socket.close() def handleRequest(self, client_socket): "用一个新的进程,为一个客户端进行服务" recv_data = client_socket.recv(1024).decode('utf-8') print(recv_data) requestHeaderLines = recv_data.splitlines() for line in requestHeaderLines: print(line) request_line = requestHeaderLines[0] get_file_name = re.match("[^/]+(/[^ ]*)", request_line).group(1) print("file name is ===>%s" % get_file_name) if get_file_name == "/": get_file_name = DOCUMENTS_ROOT + "/index.html" else: get_file_name = DOCUMENTS_ROOT + get_file_name print('打开的是{}'.format(get_file_name).encode('utf-8')) try: f = open(get_file_name, "rb") except IOError: response_header = "HTTP/1.1 404 not found\r\n" response_header += "\r\n" response_body = "====sorry ,file not found====" else: response_header = "HTTP/1.1 200 OK\r\n" response_header += "\r\n" response_body = f.read() f.close() finally: client_socket.send(response_header.encode('utf-8')) client_socket.send(response_body) client_socket.close() def main(): httpd=WSGIServer(('',7788)) print('端口号:{}'.format(7788)) httpd.serve_forever() if __name__ == '__main__': main()
分割服务器和逻辑功能代码用WSGI
WSGI允许开发者将选择web框架和web服务器分开。可以混合匹配web服务器和web框架,选择一个适合的配对
web服务器必须具备WSGI接口,所有的现代Python Web框架都已具备WSGI接口,它让你不对代码作修改就能使服务器和特点的web框架协同工作
上面的application()
函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:
-
environ:一个包含所有HTTP请求信息的dict对象;
-
start_response:一个发送HTTP响应的函数
浏览器请求页面过程:
浏览器和web之间遵守的是HTTP协议
web和框架之间遵守wsgi协议
WEB服务器接收请求返回响应
1.浏览器向web服务器发送请求
2.web服务器接收到请求后设置一个响应头(response_headers)给web框架
3.web框架通过调用response_headers得到响应头信息返回给web服务器
4.web服务器保存信息后在返回给框架
5.框架查询数据库得到响应体body返回给web服务器
6.web服务器得到响应体后在发送给浏览器