PythonNet

目录

网络编程

day02

day03

day04

day05

day06

day07

day08

day09


网络编程

网络起源 (了解)

网络目的 : 数据的传输

ISO : 国际标准化组织

OSI七层模型 ----》 网络通信的标准化流程
应用层 : 提供用户服务,具体的内容由特定程序规定
表示层 : 数据的压缩优化加密
会话层 : 建立应用连接,选择传输层服务
传输层 : 提供数据传输服务,流量控制
网络层 : 路由选择,网络互连
链路层 : 提供链路交换,具体的消息的发送
物理层 : 物理硬件,接口 网卡的规定 

osi模型优点 : 将功能分开,降低网络传输中的耦合度每一部分完成自己的功能,开发更加清晰专一

四层模型
应用层 :  应用层 表示层  会话层
传输层 :  传输层
网络层 :  网络层
物理链路层:   链路层  物理层


五层模型(tcp/ip模型)
应用层 :  应用层 表示层  会话层
传输层 :  传输层
网络层 :  网络层
链路层 :  链路层  
物理层 :  物理层

要求 : 能够按顺序说出七层模型 五层和四层模型
        知道每一层是什么作用
                对网络消息传输流程有基本了解

协议 :网络通信中,各方必须遵守的规定。包括建立什么样的连接,消息结构等。

应用层 : TFTP  HTTP  DNS  SMTP
传输层 : TCP  UDP
网络层 : IP
物理层 : IEEE

网络相关概念

主机 : host  表示一台计算机

本地使用 :  'localhost'  
             ''
                         '127.0.0.1'
网络使用 : '0.0.0.0'
            '172.60.50.60'

获取计算机名:
In [2]: socket.gethostname()
Out[2]: 'tedu'

通过计算机名获取地址:
In [3]: socket.gethostbyname('tedu')
Out[3]: '127.0.1.1'

IP地址

在网络上确定一台主机的地址
IPv4 :点分十进制 比如 192.168.1.72  0--255  
       32位二级制表示

IPv6 : 128位二进制

windows    cmd.exe 窗口 --》 ipconfig
linux      查看本机地址 ifconfig

网络连接测试
ping  172.60.50.60

特殊IP
127.0.0.1   本地测试IP
0.0.0.0    使用局域网内可用的IP
192.168.1.0  表示当前网段
192.168.1.1  通常是网络节点设备的IP (网关)
192.168.1.255  广播地址

通过域名获取服务器信息
 socket.gethostbyaddr('www.baidu.com')
('127.0.0.1', [],    ['119.75.213.61'])
   主机     主机别名   主机IP

将点分十进制IP转换为二进制
In [11]: socket.inet_aton('192.168.1.2')
Out[11]: b'\xc0\xa8\x01\x02'
将二进制转换为点分十进制IP
In [12]: socket.inet_ntoa(b'\xc0\xa8\x01\x02')
Out[12]: '192.168.1.2'

功能 : 同上面两个完全相同。只是可以选择地址类型
inet_pton(socket.AF_INET,'192.168.1.2')
inet_ntop()


域名: 网络服务器地址的网络名称

端口号 : 端口号是网络地址的一部分,在一个系统中 每个网络应用都会有一个端口号相对应。用来在接收消息时确定由谁来接收

范围 : 1--65535
1--255 一些通用的众所周知程序占用
256-1023  系统应用端口
1024 --- 65535   自用   >10000 

获取应用端口:
In [16]: socket.getservbyname('mysql')
Out[16]: 3306

字节序 
数据在内存中的存储解析方式,不同操作系统可能不同

网络字节序 : 不同的操作系统在消息收发时均按照该标准操作。


传输层服务

面向连接的传输服务  ----》 tcp协议

传输特征:

可靠的数据传输
可靠性指数据传输中 无失序 无差错 无丢失  无重复

所有消息传输前一定会建立连接,传输后一定会断开连接

三次握手: 在进行面向连接的数据传输前进行传输连接的过程
1. 客户端向服务器发送连接请求(问是否可以连接)
2. 服务器接收到连接请求进行确认,返回报文
3. 客户端收到回复,进行连接建立

四次挥手: 在进行面向连接的数据传输时,断开连接的过程
1. 主动方发送报文 告知被动方要断开连接
2. 被动方返回报文,告知收到请求,准备断开
3. 被动方再次发送报文给主动方,告知准备完毕可以断开
4. 主动方发送报文进行断开

应用情况 :适用于传输较大的内容或文件,网络情况良好,需要保证传输可靠性的情况
比如 : 聊天信息,文件的上传下载,邮件传输
        网页获取


面向无连接的传输服务 ---》 udp协议

传输特点:
不保证可靠的数据传输
没有连接过程
数据的收发都比较自由,不会受另一端制约

适用情况: 网络情况较差,对传输可靠情形要求不高。需要提升传输效率的情况
比如 : 网络视频,群聊,发送广播

问题总结:
1.osi模型问题
2.三次握手四次挥手问题
3.tcp和udp的区别


socket套接字编程
目的 : 通过编程语言提供的函数接口进行组合,更简单的完成基于 tcp 或者udp通信的网路编程

套接字 : 完成上述目标的一种编程方法

套接字分类

流式套接字(SOCK_STREAM): 传输层基于tcp的协议进行通信

数据报套接字 (SOCK_DGRAM):传输层基于udp协议进行通信

底层套接字 (SOCK_RAM):访问底层协议的套接字


TCP服务端 

import  socket

1. 创建套接字
socket.socket(socket_family = AF_INET,socket_type = SOCK_STREAM,proto = 0)
功能 : 创建一个套接字
参数 : socket_family  : 选择地址族类型 AF_INET 
        socket_type :套接字类型 SOCK_STREAM 流式
                                        SOCK_DGRAM 数据报
                proto :子协议类型,没有子协议选择 0
返回值 : 套接字对象

2. 绑定地址(IP 端口号)
sockfd.bind()
功能 : 绑定地址
参数 : 一个元组包含两项  
        第一项为IP第二项为端口号
                ('172.60.50.50',8888)

3. 将套接字设置可监听
sockfd.listen(n)
功能 : 将套接字设置为监听套接字
参数 : n是一个正整数 表示监听等待队列的大小

4. 等待接收连接请求
connfd,addr = sockfd.accept()
功能: 阻塞等待处理客户端连接
返回值 : 第一个 : 一个新的套接字用来和客户端通                     信
                    第二个 : 连接的客户端的地址


* 阻塞函数:程序运行到阻塞函数的位置,如果某种期待条件没有达成则暂停继续运行。当条件达成后会结束阻塞继续运行。

5. 收发消息
data = connfd.recv(buffersize)
功能 : 流式套接字接收消息
参数 : 一次最多接收多大的消息  字节
返回值 : 返回接收到的内容

n = connfd.send(data)
功能 : 流式套接字发送消息
参数 : 要发送的内容  要求bytes格式
返回值 : 返回实际发送的字节数

6. 关闭套接字
close()
功能:关闭套接字 tcp套接字连接断开

tcp 客户端
1. 创建套接字 
socket()
2. 请求连接
connect()
功能: 发起连接请求
参数: 是一个元组,表示服务器的地址

3. 消息收发
recv()  send()
4. 关闭套接字
close()

作业 : 

1. 口述 什么是七层模型,tcp/ip模型
         三次握手和四次挥手的过程
                 tcp协议的传输和udp协议的传输有何区别
2. 将tcp程序改写为一个通过循环可连续收发消息的程序
 

 

day02


recv() 特征
*如果连接的另一端断开连接,则recv立即返回空子串
*recv是从接收缓冲区取出内容,当缓冲区为空则阻塞
*如果一次接收不完缓冲区内容,下次会继续接收

send() 特征
*如果发送的另外一端不存在则会产生Pipe Broken
*send是向缓冲区发送内容,当缓冲区为满阻塞

网络的收发缓冲区

在内存中开辟的区域,用于发送和接受的缓冲
*协调数据收发速度
*减少和磁盘的交互


sendall()
功能:tcp套接字发送消息
参数:同send
返回值:如果发送成功返回None,否则产生异常


tcp粘包
产生原理:
*tcp传输以字节流的方式发送消息,消息之间没有边界
*发送比接受的速度快
影响:对每次发送的内容是一个独立的意思需要单独识别

如何处理粘包:
1.每次发送后加一个结尾标志
2.发送一个数据结构
3.每次放有一个间隔

基于UPD的服务端编程
1.创建套接字
sockfd = socket(AF_INET, SOCK_DGRAM)
2.绑定地址
sockfd.bind()
3.消息收发
data,addr = sockfd.recvfrom(buffersize)
功能:接收UDP消息
参数:每次最多接收下次的大小  字节
返回值:data 接收到的内容
        addr 消息发送方的地址
sockfd.sendto(data,addr)
功能:UDP消息发送
参数:data 要发送的内容 bytes
      addr 目标地址
返回值:发送多少字节
4.关闭套接字
sockfd.close()

cookie:
import sys
sys.argv


*recvfrom每次接收一个报文,如果没有接收完全则丢弃没有收到的内容

tcp流式套接字和udp数据报套接字区别
1.流式套接字采用字节流方式进行传输,而数据报套接字使用数据报形式传输数据
2.tcp套接字会产生粘包,udp不会
3.tcp编程可以保证消息的完整性,udp则不能保证
4.tcp需要listen  accept,udp不用
5.tcp消息的发送接收使用recv,send,sendall,udp使用recvfrom,sendto


socket模块和套接字属性方法
属性
s.type :套接字类型
s.family :回去地址族类型
方法
s.fileno() 
功能:获取套接字的文件描述符
文件描述符:每一个IO事件操作系统都会分配一个不同的正整数与之匹配,该整数即为此IO的文件描述符
eg:
sys.stdin  0
sys.stdout 1
sys.stderr 2

s.getsockname()
功能:获取套接字绑定的地址,未绑定默认('0.0.0.0',0)
返回值:IP元组

s.getpeername()
功能:获取连接套接字客户端的地址

s.setsockopt(level,optname,value)
功能:设置套接字选项
参数:level    设置选项类型 IPPROTO_*  SOL_*
      optname  子类选项
      value

s.getsockopt(level,optname)
功能:获取套接字选项值
参数:level 设置选项类型,optname  子类选项
返回值:获取值


udp套接字应用 ---> 广播(broadcast)
一点发送多点接收
特殊目标地址:广播地址 176.140.18.255

cookie:
'..{}..{:^10}..'.format('...','...')


tcp ---> http传输
http协议 --> 超文本传输协议
用途:网站中浏览器获取网页的过程
      编写基于http协议的数据传输
特点:
1.应用程序协议,传输层使用TCP协议
2.简单,灵活,可以使用多种编程语言操作
3.无状态的协议,即不记录用户输入的内容
4.http1.1 ---> http2.0(还在研发) 技术成熟和稳定


http请求(request)
请求格式:
  请求行
    提供具体的请求类别和请求内容
    GET    /index.html    HTTP/1.1
    请求类别   请求内容   协议版本
    请求类别:GET   获取网络资源
              POST  提交一定的附加数据
          HEAD  获取响应头
          PUT   更新服务器资源
          DELETE 删除服务器资源
          CONNECT 预留请求
          TRACE   用于测试
          OPTIONS 获取服务器性能信息
  请求头
    对请求的具体描述(键值对方式)
    Accept:text/html
    *每一个键值占一行,描述了一个特定信息
  空行
  请求体
    具体的参数或者提交的内容
    get参数或者post提交的内容

http响应(response)
响应格式:
  响应行
    反馈具体的响应情况
    HTTP/1.1    200    OK
    协议版本   响应码  附加信息
    响应码:  1xx  提示信息
              2xx  响应成功
          3xx  响应需要重定向
          4xx  客户端错误
          5xx  服务器错误
    常见:   200  访问成功
             404  请求不存在
         401  没有访问权限
         500  服务器发生未知错误
         503  服务器暂时无法执行
  响应头
    对响应内容的具体描述(键值对方式)
    Content-Encoding:gzip
    Content-Type:text/html
  空行
  响应体
    将客户端请求内容进行返回

要求:
  知道http作用
  掌握http协议 请求和响应的格式以及每一部分
  掌握http协议中请求的基本类型和作用
  知道http响应码的类型和表达含义
  了解通过http协议请求网页的流程
 

 

day03


tcp应用之 httpserver
*接收http请求
*查看http请求
*返回一个网页给客户端


IO  input  output

在内存中存在数据交换的操作可以认为是IO操作(输入输出)
内存和磁盘进行数据交换->文件读写  数据库更新
内存和终端数据交换->input print sys.stdin sys.stdout sys.stderr
内存和网络数据的交互->网络连接  recv  send  recvfrom  sendto

IO密集型程序
  在程序执行中有大量的IO操作,而较少的cpu运算操作
  消耗cpu较少,IO运行时间长

CPU(计算)密集型程序
  程序中存在大量的cpu运算,IO操作相对较少,消耗cpu大


IO分类
阻塞IO   非阻塞IO   IO多路复用   事件驱动IO  异步IO

阻塞IO:程序运行中遇到IO条件没有达成,或者传输过程中较慢的情况会出现阻塞状态
* 阻塞IO是 IO最简单的逻辑情形,也是默认状态
* 阻塞IO是效率很低的IO形态

阻塞情况:
* 因为某种条件没有达到形成阻塞
e.g.  accept   recv   recvfrom   input
* 处理IO事件的事件较长形成的阻塞
e.g.  文件读写  网络数据发送过程

非阻塞IO:在程序运行中遇到IO的情形不让其产生阻塞
实现手段:改变IO事件的属性,使其变为非阻塞
* 通常会和循环一起使用,进行条件的循环监控

s.setblocking(False)
功能:将套接字设置为非阻塞状态
参数:默认为阻塞状态  设置为False则为非阻塞


超时检测

将原本阻塞的函数,设置一个阻塞的最长时间,在时间内如果任然阻塞则不再等待

s.settimeout(sec)
功能:设置套接字的超时时间
参数:时间(s)


IO多路复用
定义:通过一个监测,可以同时监控多个IO事件的行为。当哪个IO事件可以执行,即让这个IO事件发生

IO事件就绪:IO事件即将发生的临界状态

* 在程序中存在的IO事件中选择要监测的
* 创建监测:将监测的事件注册
* 等待监测的IO事件发生,判断是什么IO事件
* 处理相应的IO

import select

select  --->  Windows linux Unix
poll  --->  linux Unix
epoll  --->  linux Unix

rs,ws,xs = select(rlist,wlist,xlist[,timeout])
功能:监控IO事件,阻塞等待监控的IO事件发生
参数:rlist    列表 存放需要等待处理的IO
      wlist    列表 存放想主动处理的IO
      xlist    列表 存放出错希望去处理的IO
      timeout   超时检测
返回值:rs  列表  rlist中准备就绪的IO
        ws  列表  wlist中准备就绪的IO
    xs  列表  xlist中准备就绪的IO

* 在处理IO时不要形成死循环,让一个客户端单独占有服务端
* IO多路复用形成一种可以同时处理多个IO的效果,效率较高


位运算
按照二进制位进行运算操作
&    与
|    或
^    异或
<<   左移  右侧补0
>>   右移  挤掉右侧数字

使用:
  在底层硬件时操作寄存器
  做标志位的过滤


poll 方法实现IO多路复用
1.创建poll对象
p = select.poll()
2.注册关注的IO
p.register(s, POLLIN | POLLHUP)

p.unregister(s)

事件类别
POLLIN    rlist
POLLOUT   wlist
POLLERR   xlist
POLLHUP   断开
POLLPRI   紧急处理

3.监控IO
events = p.poll()
功能:监控关注的IO事件
返回值:返回发生的IO事件
events 时一个列表 [(fileno,event1),(fileno,event2),...]
每个就绪IO对应列表中的一个元组(描述符,就绪事件)
IO地图:{s.fileno():s}  需要不断维护
4.处理IO事件


作业:
1.熟练select_server.py代码
2.了解 IO多路复用原理机制
3.写一个 select 服务端,同时关注客户端连接,客户端输入和终端输入(sys.stdin)。将客户端和终端输入的内容,全都写入到一个文件中


day04

epoll
使用方法:代码基本与poll一致
* 将生成的对象改为 p = epoll()
* 将事件类别名称改为epoll关注事件类别

区别
epoll:效率要高于select 和 poll
epoll(内核决定返回就绪的IO)
select/poll(内核将所有IO全部返回,应用层决定哪个就绪)
epoll 的触发机制更多 --> EPOLLET(边缘触发)
水平触发:就绪未处理IO不断轮询
边缘触发:当有IO未处理时,不在处理,当下次其他IO需要处理时,一起处理

本地套接字

cookie
linux下文件类型
b  块设备文件(驱动)
c  字符驱动设备文件(鼠标,键盘)
d  目录
-  普通文件(文本视频压缩包)
l  链接文件
s  套接字文件
p  管道文件

本地套接字作用:
  用于本地不同程序间,进行数据传输
1.创建套接字
sockfd = socket(AF_UNIX, SOCK_STREAM)
2.绑定套接字文件,如果文件不存在则自动创建
sockfd.bind(file)
3.监听
listen
4.消息收发
recv  send

cookie
os.path.exists(file)
功能:判断一个文件是否存在
参数:文件
返回值:True / False

os.remove()
os.unlink()
功能:删除一个文件
参数:要删除的文件


网络基础总结:
1.OSI七层模型  TCP/IP模型
2.TCP和UDP区别
3.三次握手和四次挥手过程和作用
4.什么是IO多路复用,IO的基本形态
5.套接字的种类,套接字类型的区别

程序实践:
1.tcp套接字传输的基本模型
2.udp套接字传输的基本模型
3.IO多路复用select poll 使用
4.http协议基本原理的实现

***********************************************


多任务编程

意义:充分利用计算机资源,同时运行多个任务,提高程序整体的执行效率
定义:通过程序利用计算机的多个核心达到同时执行多个任务的目的。一次达到提升程序效率的目的

实施方案:
多进程编程
多线程编程

并行:
  多个计算机核心在同时处理多个任务,这是多个任务之间是并行关系
并发:
  同时处理运行多个任务,内核在多个任务间不断切换达到多个任务都会被执行的处理效果,此时多个任务间是并发关系

同一个计算机内核在同一时刻只能运行一个程序

进程:(process)
  程序在计算机中的一次执行过程
  进程是一个动态的过程,占有计算机资源,有一定的生命周期
程序:
  程序是一个可执行文件,是静态的,占有磁盘,不占有计算机资源

* 同一个程序不同的运行过程是不同的进程。因为分配的资源和生命周期都不相同

进程的创建流程
1.用户启动一个程序或者调用接口发起进程的创建
2.操作系统接收用户请求,分配计算机资源,创建进程
3.操作系统将一定状态的进程提供给用户使用
4.用户利用操作系统提供的进程完成任务

CPU时间片
  如果一个进程占有cpu,此时我们称为该进程占有cpu的时间片。多个进程任务会轮流占有cpu时间片形成并发效果。

进程信息
PCB (进程控制块)
  进程创建后会自动在内存产生一个空间存放进程信息

进程信息:进程的ID  进程占有内存的位置  创建时间  创建用户

查看系统该进程信息:ps -aux
PID(process ID):在操作系统中每个进程都有唯一的PID值是由系统分配的。

进程特征:
* 进程是操作系统分配资源的最小单元
* 每个进程拥有自己独立的运行空间(虚拟内存空间)
* 进程之间运行相互独立互不影响

进程的状态:
三态
* 就绪态:进程准备执行条件,等待系统分配处理器资源进入运行态
* 运行态:进程占有cpu处于运行态
* 等待态:进程暂时不具备运行条件,需要阻塞等待

五态
  在三态基础上增加了 新建 和 终止
  新建:创建一个新的进程,获取系统资源的过程
  终止:进程执行结束,释放资源的过程

STAT表示进程状态
D  等待态  阻塞  不可中断等待态
S  等待态  睡眠  可中断等待态
T  等待态  暂停  暂停执行
R  运行态(就绪态)
Z  僵尸

+  前台进程(在终端运行)
<  有较高优先级的进程
N  较低优先级进程
s  会话组
l  有进程连接


top命令(查看进程状态-动态)
< > 翻页  q 退出

nice 命令 优先级(-20~19) 最高-20
  以指定优先级运行一个程序
e.g. 
nice -9 ./while.py  (以9的优先级运行程序)
sudo nice --9 ./while.py (以-9优先级运行)


cookie
首行添加
#! /usr/bin/python3
修改程序程序添加可执行权限
chmod 777 while.py
可以直接执行
./while.py


父子进程
  在系统中处理初始化进程每个进程都已一个父进程,可能有0个或多个子进程。由此形成进程间的父子关系。

便于进程管理,父进程发起创建子进程请求
查看进程树:pstree
查看父子进程PID:ps -aux

要求:
1.什么是进程,进程和程序的区别
2.了解进程的特征和基本区别
3.理解并发和并行的区别
4.清除进程的状态转换

os.fork  创建进程
pid = os.fork()
功能:创建进程
返回值:失败返回一个负数
        成功:在原有进中返回新进程的pid号,在新进程中返回0

* 子进程会复制父进程全部的内存空间包括代码段
* 子进程会从fork的下一句开始执行
* 父进程中fork返回值即为新创建子进程的pid号
* 父子进程不一定谁先执行,执行上互不干扰抢占时间片
* 使用if 语句结构使父子进程执行不同的代码几乎是fork创建进程的固定结构
* 在子进程中对变量等其他内容的修改,不会影响父进程中的内容
* 子进程虽然复制父进程内容,但是也有自己的特有属性特征。比如PID号 PCB内存区间等


获取进程PID
os.getpid()
功能:获取进程的PID号
返回值:返回进程的PID号

os.getppid()
功能:获取 父进程 的PID号
返回值:返回 父进程 的PID号

进程退出
os._exit(status)
功能:退出一个进程
参数:进程的退出状态(整数 必选)

sys.exit([status]) 
功能:退出一个进程
参数:默认为0
      如果传入一个整数则同 _exit(n)
      传入一个字符串,则在退出时打印该字符串

* sys.exit() 是通过异常使程序退出,可以用try语句捕获(SystemExit),退出原因是[status]
* os._exit() 退出不可逆


作业:
1.理解进程fork
2.熟悉进程的理论内容
 

 

day05


孤儿进程:
  当父进程先于子进程退出时,子进程就会变成孤儿进程

* 孤儿进程会被系统指定进程收养,即系统进程会成为孤儿进程新的父进程。系统进程会自动处理孤儿进程退出状态


僵尸进程:
  子进程先于父进程退出,父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程

* 僵尸进程会滞留部分PCB信息在内存中,大量的僵尸进程会消耗系统给的内存资源,所以要尽量避免僵尸进程的产生


如何避免僵尸进程产生
* 父进程先退出
* 父进程处理子进程退出状态

pid, status = os.wait()
功能:在父进程中阻塞等待子进程的退出
返回值:pid 退出的那个子进程PID号
        status 子进程的退出状态

获取原理退出状态
os.WEXITSTATUS(status)

pid, status = os.waitpid(pid, option)
功能:在父进程中阻塞等待子进程的退出
参数:pid  -1  表示等待任意子进程退出
           >0  表示等待对应PID号的子进程退出
      option 0 表示阻塞等待
             WNOHONG 表示非阻塞
返回值:pid 退出的那个子进程PID号
        status 子进程的退出状态


创建二级子进程
  父进程创建子进程等待子进程退出
  子进程创建下一级子进程,然后立即退出
  二级子进程成为孤儿进程,处理具体工作

类似于qq群聊
1.进入聊天室,需要输入姓名,且不能重复
2.有人进入聊天室此时会向其他人发起通知
  xxx 进入了聊天室
3.如果一个人发信息,则其他人都能收到
  xxx 说: xxx
4.如果某人退出聊天室,其他人也会收到通知
  xxx 退出了聊天室
5.服务端可以喊话,此时群里所有人都能收到服务端消息
  管理员 说:xxx

整体结构:
  如何封装
  使用什么样的技术手段

服务端   客户端

在客户端和服务端每个功能封装为一个函数

技术方案
  转发:一个客户端发送给服务器,服务器发送给其他人
  套接字使用 udp 完成操作
  用户存储:列表 字典(可变类型,能够遍历提取)
            地址,用户名
  发送和接收消息的控制:发送和接收使用多进程分离互不影响

注意事项:
1.注重封装
2.分段测试

代码编写流程
  先搭建通信
  创建多进程
  每个进程功能确定
  实现每个功能模块

功能细节梳理
  进入聊天室
    客户端:创建用户名
            将信息发送给服务器
        接收到服务器返回结果判断下一步执行什么
    服务端:接收消息
            判断请求类型
        判断是否可以登录(判断姓名是否已经存在)
        返回给客户端是否登录(如果可以服务端会将姓名插入到存储结构)
        给所有人发送消息
  聊天
    客户端
      创建父子进程收发消息
      向客户端发送 聊天消息+用户名+请求类型
      接收服务器回复
      接收服务端发来的 聊天消息
    服务端
      创建父子进程收发消息
      接收客户端发送 聊天消息+用户名信息+请求类型
      以 用户名+聊天消息方式 转发给其他人
  退出聊天室
    客户端
      客户端发送 退出信息+用户名
      接受回复
      退出程序
    服务端
      接收客户端发送 退出信息+用户名
      删除已退出用户信息,并向所有人发送 xxx已退出

multiprocessing 模块创建进程(标准库模块)
1.需要将要做的事情封装成函数
2.使用multiprocessing提供的Process类创建进程对象
3.通过进程对象和Process初始化进程进行进程的设置,绑定函数
4.启动进程,会自动执行绑定的函数
5.完成进程回收

创建进程对象
Process()
功能:创建进程对象
参数:target:要绑定的函数
      name:给进程起的名称(默认Process-1)
      args:元组 用来给target函数位置传参
      kwargs:字典 用来给target函数键值传参

p.start()
功能:启动进程 自动运行target绑定的函数。此时进程被创建

p.join([timeout])
功能:阻塞等待子进程退出
参数:超时检测

* 使用multiprocessing 创建进程子进程同样复制父进程的全部内存空间,之后有自己独立空间,执行上互不干扰
* 子进程也是有自己特有的PID等资源
* 如果不使用join回收可能会产生僵尸进程
* 使用multiprocesing创建子进程,一般父进程功能就是创建子进程回收子进程,所有事件交给子进程完成


作业:
1.梳理聊天室代码
2.对进程概念和创建过程进行巩固
3.加深对http协议的理解
4.编程:使用父子进程复制一个文件,分别复制文件的上半部分和下半部分(以字节数区分)到新的文件中


 

day06

Process(target, name, args, kwargs)

name:给进程起名字
args:给进程元组传参
kwargs:给进程字典传参

p.pid : 创建的新的进程的PID号
p.is_alive() : 判断进程是否alive状态

p.daemon : 如果设置为True,则主进程退出时子进程也会结束
* daemon 属性设置要在start()前
* 设置daemon为True则一般不需要加join

os.path.getsize('./xxx') 获取文件大小


如果多个子进程拷贝同一个父进程中的对象内容,则多个子进程使用的是同一个对象,如文件,套接字,队列,管道。
如果是在创建子进程后单独创建的对象,则多个子进程各部不同


进程的缺点
  进程在创建和销毁的过程中消耗的资源相对较多

进程池技术
产生原因:如果有大量的任务需要多进程完成,而任务周期又比较短且需要频繁的创建。此时可能产生大量进程频繁创建销毁的情况,消耗计算机资源较大


使用方法:
  创建进程池,在池内放入适当的数量的进程
  将事件封装函数,放入到进程池
  事件不断运行,直到所有放入进程池事件运行完成
  关闭进程池,回收进程

from multiprocessing import Pool

Pool(processes) 
功能:创建进程池对象
参数:进程数量
返回:进程池对象

p.apply_async(func, args, kwds) -- 异步执行
功能:将事件放入进程池执行
参数:fun 要执行的事件函数
      args 以元组为fun传参
      kwds 以字典为fun传参
返回值:返回事件对象的内存地址,通过get()属性函数可获取func的返回值

p.apply(func, args, kwds) -- 同步执行
功能:将事件放入进程池执行
参数:fun 要执行的事件函数
      args 以元组为fun传参
      kwds 以字典为fun传参

p.close()
功能:关闭进程池,无法再加入事件

p.join()
功能:回收进程池

p.map(func, iter)
功能:将要执行的事件放入到进程池
参数:func 要执行的函数
      iter 迭代对象,为func传参
返回值:事件函数的返回值列表


进程间通信(IPC)
由于进程间空间独立,资源无法共享,此时在进程间通信就需要专门的通信方法


进程间通信方法:管道,消息队列,共享内存,信号,信号量,套接字


管道通信 Pipe
在内存中开辟一块空间,形成管道结构,多个进程使用同一个管道,即可通过对管道的读写操作进行通信

multiprocessing --> Pipe

fd1,fd2 = Pipe(duplex=True)
功能:创建管道
参数:默认表示双向管道
      如果设置为False则为单向管道
返回值:两个管道对象,分别表示管道的两端
        如果是双向管道,均可读写
    如果是单向管道,则fd1只读,fd2只写


fd.recv()
功能:从管道读取信息
返回值:读取到的内容
* 当管道为空则阻塞

fd.send(data)
功能:向管道写入内容
参数:要写入的内容
* 当管道满时则阻塞
* 可以写入几乎所有的python数据


消息队列
  先进先出
在内存中开辟队列结构空间,对多个进程进程课件。多个进程操作同一个队列对象可以实现消息的存取工作


创建队列
q = Queue(maxsize=0)
功能:创建队列对象
参数:maxsize 默认表示系统自动分配队列空间
      如果传入正整数则表示最多存入的消息
返回值:队列对象

q.put(data[,block,timeout])
功能:向队列中存入消息
参数:data 存入的消息 (支持python数据类型)
      block 默认为True 表示当队列满时阻塞
            设置为False 则为非阻塞
      timeout 超时时间

data = q.get([block,timeout])
功能:获取队列消息
参数:block 默认为True 表示队列空时阻塞
            设置为False 表示非阻塞
      timeout 表示超时时间
返回值:返回获取到的消息

q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 获取队列中的消息数量
q.close() 关闭队列

共享内存
在内存中开辟一段孔家,存储数据,对多个进程课件。每次写入共享内存的数据会覆盖之间的内容

from multiprocessing import Value,Array

shm = Value(ctype,obj)
功能:开辟共享内存空间
参数:ctype 字符串 要转变的c类型
      obj  共享内存的初始化数据 (单一数据)
返回值:返回共享内存对象

shm.value 表示共享内存中的值


shm = Array(ctype,obj)
功能:开辟共享内存空间
参数:ctype 字符串 要转变的c类型
      obj  要存入共享内存的数据
          * 列表、字符串 表示要存入的内容:要求类型相同
      * 整数,表示要开辟几个单元空间
返回值:返回共享内存对象 可迭代对象

            管道      消息队列       共享内存
开辟空间    内存        内存           内存
读写方式  两端读写    先进先出     每次覆盖上次内容
          双向/单向
效率        一般        一般           较高
应用   多用于父子进程  应用灵活广泛  复杂,需要同步互斥操作

作业:熟练进程间通信和进程池的使用
复习类的使用


day07


p.name
p.pid
p.is_alive()  查看进程状态
p.daemon


自定义进程类
  继承Process 重写run

进程池
Pool() 创建进程池
apply_async() 添加事件

进程间通信
管道 --- Pipe()
消息队列 ---- Queue() ----- q.put  q.get q.full
共享内存 ----- Value  Array


************************************************

信号

一个进程向另外一个进程通过信号的方式传递某种讯息,接收方在接收到信息后作出相应的处理


kill -l  查看信号
kill -sig PID  向一个进程发送信号

关于信号
信号名称:系统定义,名字或者数字
信号含义:系统定义,信号的作用
默认处理方法:当一个进程接收到信号时,默认产生的效果---终止进程,暂停进程,忽略发生

SIGNUP --- 断开连接
SIGINT --- Ctrl+C --- 终止
SIGQUIT --- Ctrl+\ --- 终止
SIGKILL --- 终止进程(没有非默认方法)
SIGALRM --- 时钟信号 ----终止
SIGSTOP ---- 暂停进程(没有非默认方法)
SIGTSTP --- Ctrl+Z ---暂停进程
SIGCHLD --- 子进程改变状态是,父进程会收到--忽略

python信号处理

os.kill(pid,sig)
功能:发送一个信号给某个进程
参数:pid 给哪个进程发送信号
      sig 发送什么信号

signal.alarm(sec)
功能:设置时钟信号,在一定时间后给自身发送SIGALRM信号
参数:sec 时间(秒)
* 一个进程中只能有一个时钟,后来的会覆盖前面的时钟

同步:程序按照步骤一步一步执行,呈现一个先后性和顺序性
异步:程序在执行中利用内核功能帮助完成必要的辅助操作,不影响应用层持续执行

signal.pause()
功能:阻塞进程,等待一个信号

signal.signal(sig,handler)
功能:处理信号
参数:sig 要处理的信号
      handler 信号处理方法
         可选值:SIG_DFL 表示使用默认方法处理
             SIG_IGN 表示忽略这个信号
         func 自定义函数处理
         自定义函数格式:
       def func(sig,frame)
          sig:接收到的对象
          frame:信号结构对象

* signal函数也是一个异步处理函数,只要执行了该函数,则进程任意时候接收到相应信号都会处理

* signal是不能处理SIGKILL SIGSTOP的
* 父进程中可以用singnal(SIGCHLD,SIG_IGN)将子进程的退出交给系统处理
* 信号是一种异步的进程间通信方式

信号量
  给定一定数量,对多个进程可见,并且多个进程根据信号量的多少确定不同的行为

  sem = Semaphore(num)
  功能:创建信号量对象
  参数:信号量的初始值
  返回:信号量对象

  sem.acquire()  将信号量数量减1  当数量为0时阻塞
  sem.release()  将信号量数量加1  
  sem.get_value()  获取当前信号量的值

同步互斥机制
目的:解决对共有资源产生的资源争夺

临界资源:多个进程或线程都能操作的资源
临界区:操作临界资源的代码段

同步:同步是一种合作关系,为完成某个任务,多进程或多线程之间形成一种协调关系,安装约定执行,相互告知,共同完成任务
互斥:互斥是一种制约关系,当一个进程或者线程进入临界区会进行枷锁操作。此时其他进程(线程)在企图使用临界资源时就会阻塞,知道资源被释放才能使用


Event事件

from multiprocessing import Event

创建时间对象
e = Event()

事件阻塞
e.wait([timeout])
功能:使进程处于闭塞状态,直到事件对象呗set

事件设置 e处于设置状态,e.wait()不在阻塞
e.set()

事件清除 e处于未设置状态,e.wait会阻塞
e.clear()

事件判断,判断e的当前状态
e.is_set()


锁 Lock
multiprocessing ---> Lock
创建锁对象
lock = Lock()

lock.acquire()  上锁
lock.release()  解锁

* 如果一个锁对象已经被上锁则在调用acquire会阻塞

with lock:  上锁
    ....
    ....
            解锁


多线程 thread
  线程也是一种多任务编程方式,可以使用计算机的多核资源
  线程被称为轻量级进程

线程特征:
  一个进程可以包含多个线程
  线程计算机内核使用的最小单位
  线程也是一个运行过程,也要消耗计算机资源
  多线程共享共用进程的资源
  线程也有自己的特征属性,TID,指令集,线程栈
  多个线程之间独立运行互不干扰
  线程创建删除消耗的资源要小于进程


threading 模块使用

threading.Thread()
功能:创建线程对象
参数:target  线程函数
      name  线程名称  默认为thread-1,thread-2...
      args  元组  给线程函数位置传参
      kwargs  字典  给线程函数字典传参
返回:线程对象

t.start()  启动线程
t.join([timeout])  回收线程

t.is_alive()
t.name
t.setNname()


默认情况下主线程的结束不会影响到分支线程的执行
如果设置为True 则主线程退出分支线程也会退出

设置方法
t.daemon = True
t.setDaemon(True)

判断daemon属性
t.isDaemon()

* 线程daemon属性的设置在start前
* 一般设置daemon后不会再使用join

创建自己的线程类
步骤:
1.继承 Thread类
2.运行 Thread类中的__init__方法以获取父类原有属性
3.重写run方法


 

day08


信号:在进程间通过信号传递信息
  os.kill(pid,sig)
  signal.alarm(sec)
  signal.pause()
  signal.signal(sig,handler)

信号量  semaphore
acquire()
release()
get_value()


tftp 文件服务器
1.文件处理
2.类的封装
3.网络

线程的同步互斥

线程Event
创建对象
e = Treading.Event()

事件阻塞函数
e.wait([timeput])
设置事件
e.set()
清除事件
e.clear()

python 线程的GIL问题
GIL(全局解释器锁)

python ---> 支持线程操作 ---> IO同步互斥问题 ---> 加锁 ---> 超级锁,给解释器加锁
后果:一个解释器,同一时刻只能解释一个线程,此时其他线程需要等待。大大降低了python线程的执行效率

python GIL问题解决方案
* 修改c解释器
* 尽量使用多进程进行并行操作
* python线程可以用在高延迟多阻塞的io情形
* 不使用cpython --> c# java 做解释器


进程和线程的区别和联系
1.两者都是多任务编程的方式,都能够使用计算机的多核
2.进程的创建删除要比线程消耗更多的计算机资源
3.进程空间独立,数据安全性好,有专门的进程间通信方法
4.线程使用全局变量通信,更加简单,单往往要与同步互斥机制共用
5.一个进程可以包含多个线程,线程共享进程的资源空间
6.进程线程都有自己特有的资源,如命令,属性,id等


使用情况:
* 一个进程中并发任务较多,比较简单,适合使用多线程
* 如果数据程序比较复杂,特别是可能多个任务通信比较多的时候,要考虑到使用线程同步互斥的复杂性
* 多个任务存在明显差异,和功能分离的时候没有必要一定写入到一个进程中
* 使用python考虑线程GIL问题


要求:
  1.进程线程的区别和关系
  2.进程间的通信方式及特点
  3.同步和互斥是什么回事,用什么方法实现同步互斥
  4.什么是僵尸进程,怎么处理的
  5.python线程的效率怎么样,gil是怎么处理的


**********************************************


服务器模型

硬件服务器:主机
厂商:IBM  HP  联想  浪潮

软件服务器:编写的服务器程序,依托硬件服务器运行。提供给用户一定的功能服务。


服务器种类:
webserver ---> 网络的后端应用程序,提供数据处理和逻辑处理

httpserver ---> 接收http请求,返回http响应

邮箱服务器 ---> 处理邮件请求,进程邮件收发

文件服务器 ---> 提供文件的上传下载存储


功能实现:网络连接,逻辑处理,数据运算,数据交互,协议实现,网络数据传输.....(后端功能)

模型结构:C/S  客户端/服务器模型
          B/S  浏览器/服务器模型


网络服务器基础

循环服务器:单进程服务器,循环接收客户端请求,处理请求。处理完毕再接收下一个请求

特点:每次只能处理一个客户端请求
      如果客户端长期占有服务器则无法处理其他客户端请求
 
优点:实现简单,占用资源少
缺点:无法同时处理多个客户端,体验差
使用情况:任务短暂,可以快速完成,udp比tcp更适合循环


并发服务器:能够同时处理多个客户端任务请求

  IO并发:IO多路复用  协程
    优点:可以实现IO的并发操作,占用系统资源少
    缺点:不能监控cpu密集的情况,不能长期阻塞消息收发
  
  多进程/多线程并发:
    为每个客户端单独提供一个进程/线程处理客户端请求


多进程并发模型
使用fork完成并发
1.创建套接字,绑定,监听
2.等待接收客户端连接请求
3.创建新的进程处理客户端请求
  父进程继续等待连接其他客户端
4.客户端退出  对应子进程也要结束

tftp文件服务器

项目功能:
* 客户端有简单的页面命令提示
* 功能包含:
    1.可以查看服务区文件库中的文件列表
    2.可以下载其中的某个文件到本地
    3.可以上传客户端文件到服务器文件库
* 服务器需求:
    1.允许多个客户端同时操作
    2.每个客户端可能会连续发送命令

技术分析:
1.tcp套接字跟适合文件传输
2.并发方案 ---> fork 多进程并发
3.对文件的读写操作
4.获取文件列表 ---> os.listdir()
  粘包处理

整体结构设计
1.服务器功能分装在类中(上传,下载,查看列表)
2.创建套接字,流程函数调用  main()
3.客户端负责发起请求,接收回复,展示
  服务端负责接收请求,逻辑处理

编程实现
1.搭建整体结构,创建网络连接
2.创建多进程和类的结构
3.每个功能模块的实现

 

day09


回顾

线程
  线程通信 ---> 全局变量
  线程的同步互斥 ---> Event Lock
  python  GIL 问题 

服务器模型
  循环模型
    每次只能处理一个客户端请求
  并发模型
    IO并发:IO多路复用  协程
    多进程、多线程并发
      每当有一个客户端就创建一个新进程

多进程并发
tcp + fork


******************************************
文件服务器
cookie
os.listdir(path)
功能:获取文件列表

os.path.isfile(obj)  判断一个文件是否为普通文件
os.path.isdir(obj)  判断一个文件是否为目录

多线程并发

threading 模块完成多线程并发
对比多进程并发
优势:资源消耗少
缺点:需要注意对共享资源的操作影响


实现步骤:
1.创建套接字,绑定,监听
2.接受客户端连接技术,创建新的进程
3.主线程继续等待其他客户端连接,分支线程执行客户端具体请求
4.处理完客户端请求后分支线程自然退出,关闭客户端套接字

socket 并发集成模块
python2 --> SocketServer
python3 --> socketserver

功能:通过模块提供的接口组合可以完成多进程/多线程 tcp/udp的并发程序

'StreamRequestHandler',  处理tcp请求
'DatagramRequestHandler',  处理udp请求
 
 'ForkingMixIn',   创建多进程
 'ThreadingMixIn',   创建多线程

 'TCPServer',  创建tcp server
 'UDPServer',  创建udp server

 'ForkingTCPServer',   TCPServer+ForkingMixIn
 'ForkingUDPServer',   UDPServer+ForkingMixIn

 'ThreadingTCPServer',   TCPServer+ThreadingMixIn
 'ThreadingUDPServer',   UDPServer+ThreadingMixIn


基于多线程并发的 HTTPServer

1.接收浏览器http请求
2.对请求进行一定解析
3.根据解析结果返回对应的内容
4.如果没有请求内容则返回404
5.组织Response格式进行回发

升级:
* 使用多线程并发
* 增加了具体请求解析和404
* 使用类进行封装
* 增加了一定的数据获取能力
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值