zoukankan      html  css  js  c++  java
  • 网络编程与并发变编程复习

    软件开发架构

    c/s:
    Client:客户端

    ​ Server:服务端

    ​ 优点:

    ​ 占用网路资源少,软件的使用的稳定

    ​ 缺点:

    ​ 服务端更新后,客户端也得跟着更新

    ​ 需要使用多个软件,需要下载多个客户端

    B/S:

    ​ Browser:浏览器(客户端)

    ​ Server:服务器

    服务端与客户端作用:

    ​ 服务端:24小时不间断提够服务

    ​ 客户端:需要体验服务端时,再去连接服务端,并享受服务

    一网络编程

    1 互联网协议OSI七层协议

    ​ 1)应用层

    ​ 2)表示层

    ​ 3)会话层

    ​ 4)传输层

    ​ 5)网络层

    ​ 6)数据链路层

    ​ 7)物理连接层

    ​ —物理连接层:基于电信号发送二进制数据

    ​ —数据链路层:规定好电信号的分组方式,必须有网卡

    ​ Mac地址:12位唯一的16进制字符串

    ​ 前6位:厂商号

    ​ 后6位:流水号

    ​ —以太网协议:在同一局域网内通信

    ​ 单播:1对1对话

    ​ 广播:多对多对话

    ​ —广播风暴

    ​ —不能跨局域网通信

    ​ —网络层

    ​ — ip:定位局域网的位置

    ​ —port:唯一标识一台计算机上一个应用程序

    ​ —ARP协议:将Mac地址获取,并解析程ip和port

    ​ — 传输层

    ​ —TCP特点:TCP协议称之为流失协议

    ​ 若想要通信,必须建立连接,并建立双向通道

    1572006920181

    ​ —三次握手,四次挥手

    ​ — 三次握手建连接

    ​ —客户端往服务端发送请求建立连接

    ​ —服务端要确认客户端的请求,并往客户端也发送请求建立连接

    ​ —客户端接收到服务端建立连接的请求,并返回确认

    ​ —建立双向通道

    ​ —双向通道:

    ​ —反馈机制

    ​ 客户端往服务端发送请求获取数据,服务端务必返回数据,客户端确认收到

    ​ 反则会反复发送,一直到某个时间段内,会停止发送

    ​ —四次挥手断连接

    ​ —客户端往服务端发送断开连接请求,服务端返回确认收到

    ​ —服务端再次发送断开连接请求

    ​ —客户端确认收到

    ​ —最终确认断开连接

    1572006966624

    ​ —UDP

    ​ 1)数据不安全

    ​ 2)不需要建立双向通道

    ​ 3)传输速度快

    ​ 4)不会有粘包问题

    ​ 5)客户端发送数据,不需要服务端确认收到,爱收不收

    TCP与UDP的区别:
    

    ​ TCP:比喻成再打电话

    ​ UDP:比喻成发送短信

    ​ —应用层

    ​ —FTP

    ​ —HTTP:可以携带一堆数据

    ​ —HTTP + SSL

    2 socket

    ​ socket用来’写套接字客户端与服务端的模块,内部帮我们封装好了7层协议需要做的事情

    3 手撸socket套接字模板

    服务端

    import socket

    server = socket.socket()

    server.bind((ip,port))

    server.listen(5) # 半连接池:可以接待6个客户端

    conn,addr = server.accept() # 监听连接

    data = conn.recv(1024) # 接受消息

    conn.send('消息内容'.encode('utf-8')) # 发送消息

    客户端

    import socket

    client = socket.socket()

    client.connect((‘ip,port’))

    client.send() # 发送数据

    client.recv(1024) # 接受消息

    4 subprocess(了解)

    用来通过代码往cmd创建一个管道,并且发送命令和接受cmd返回的结果

    import subprocess
    obj = subprocess.Popen(
        'cmd命令',
        shell=True,
        # 接收正确结果
        stdout=subprocess.PIPE,
        # 接收错误结果
        stderr=subprocess.PIPE
    )
    success = obj.stdout.read()
    error = obj.stderr.read()
    msg = success + error
    
    5 粘包问题

    1不能确认对方发送数据的大小

    2在短时间内,间隔时间短,并且数据量小的情况下,默认将这些数据打包成一个

    ​ 多次发送数据------------->一次发送

    6 struct解决粘包问题

    初级版:

    i:4

    可以将一个数据的长度打包成一个固定长度的报头

    struct.pack('模式i', '原数据长度')

    data = 'gsjfdfytaytsf'

    headers = struct.pack('i' ,len(data)) # 打包成报头

    data = struct.unpack('i' ,headers)[0] # 解包获取数据的真实长度

    注意:以什么方式打包,必须以什么方式解包

    升级版:
    先将数据存放到字典中,将字典打包发送发送过去

    ​ —字典的好处:
    ​ —真实数据长度

    ​ —文件的描述信息

    ​ —发送的数据更小

    ​ dic = {'data_len':10000000000000000000000000444444444444444444,

    ​ 文件的描述信息}

    7 上传大文件数据

    客户端

    dic = {

    ​ 文件大小,

    ​ 文件名

    ​ }

    with open(文件名,‘rb’)as f:
    for line in f:
    client.send(line)

    服务端

    dic = {

    ​ 文件大小,

    ​ 文件名

    ​ }

    init_recv = 0

    with open(文件名,'wb' ) as f:

    ​ while init_recv < 文件大小:

    ​ data = conn,recv(1024)

    ​ f.write(data)

    ​ init_recv += len(data)

    10 socketserver(现阶段,了解)

    —可以支持并发

    import socketserver

    定义类

    TCP:必须继承BaseRequestHandler类

    class MyTcpServer(socketserver.BaseRequestHandler):

    ​ —handle

    ​ #内部实现了

    ​ server = socket.socket()

    ​ server.bind(('127.0.0.1,8080'))

    ​ server.listen(5) --------

    ​ while True:
    ​ conn,addr = server.accept()

    ​ print(addr)

    必须重写父类的handle,当客户端连接时回调用该方法

    def handle(self):

    ​ print(self.client_adddress)

    ​ while True:

    ​ try:

    ​ request.recv(1024) == conn.recv(1024) # 接受消息

    ​ data = self.request.recv(1024).decode('utf-8')

    ​ send_msg = data.upper()

    ​ self.request.send(send_msg.encode('utf-8'))

    ​ except Exception sa e:

    ​ print(e)

    ​ break

                
    TCP:
        SOCK_STREAM
        conn.recv()
    
    UDP模板:
        SOCK_DGRAM
        server.recvfrom()
    
        - 服务端
            import socket
            server = socket.socket(
                type=socket.SOCK_DGRAM
            )
            server.bind(
                (ip, port)
            )
            data, addr = server.recvfrom(1024)
            server.sendto(data, addr)
    
        - 客户端
            import socket
            client = socket.socket(
                type=socket.SOCK_DGRAM
            )
            ip_port = (ip, port)
    
            client.sendto(data, ip_port)
    
            data, _ = client.recvfrom(1024)
            print(data)
    

    二 并发编程

    12 多道技术

    单道

    多道:切换+保存状态

    ​ —空间上的复用

    ​ 支持多个程序使用

    ​ —时间上的复用

    ​ 遇到io操作就会切换程序

    ​ 程序占用cpu时间过长切换

    13 并行与并发

    ​ 并发:看起来像同时运行:多道技术

    ​ 并行:真正意义上的同时运行,多核下

    14 进程

    ​ 进程是资源单位,每创建一个进程都会生成一个名称空间,占用内存资源

    ​ —程序与进程

    ​ 程序就是一堆代码

    ​ 进程就是一堆代码运行的过程

    ​ —进程调度

    ​ —时间片轮转法

    ​ 10个进程,将固定时间,等分程10份时间片,分配给每一个进程

    1572007058606

    ​ —分级反馈队列

    ​ 1级别

    ​ 2级别

    ​ 3级别

    ​ —进程的三种状态:

    ​ —就绪态:创建多个进程,必须要排队准备运行

    ​ —运行态:进程开始运行,1结束 2阻塞

    ​ —阻塞态:当运行态遇到io操作,就会进入阻塞态

    		——同步与异步:提交任务的方式
    		
    		同步:同步提交,串行,一个任务结束后,另一个任务才能提交并执行
    		
    		异步:异步提交,多个任务可以并发执行
    		
    		- 阻塞与非阻塞
        - 阻塞:
            阻塞态
        - 非阻塞:
            就绪态
            运行态
    
      - 同步和异步、阻塞和非阻塞的区别。
            两者是不同的概念,不能混为一谈.态
    

    —创建进程的两种方式

    ​ p = Process(target = 任务,args = (任务的参数,))

    ​ p.daemon = True # 必须放在start()前,否则报错

    ​ p.start() # 向操作系统提交创建进程的任务

    ​ p.join # 向操作系统发送请求,等所有子进程结束,主进程在结束

    二 :
    class Myprocess(Process):

    ​ def run(self): # self === p

    ​ 任务过程

    ​ p = Myprocess()

    ​ p.daemon = True # 必须放在start()前,否则报错

    ​ p.start() # 向操作系统提交创建进程的任务

    ​ p.join() # 向操作系统发送请求,等所有子进程结束,主进程在结束

    —回收进程资源的两种条件:

    ​ —调用join让子进程结束后,主进程才能结束

    ​ —主进程正常结束

    15僵尸进程与孤儿进程(了解)

    ​ 僵尸进程:凡是子进程结束后,pid号还在,主进程意外死亡,没法给子进程回收资源

    ​ —每个子进程结束后,都会变成僵尸进程(pid)

    孤儿进程:凡是子进程没有结束,但是主进程意外死亡,操作系统优化机制(孤儿院),

    会将没有主进程,并且存活的进程,在该进程结束后回收资源

    16 守护进程

    ​ 只要主进程结束,所有的子进程都必须结束

    17 互斥锁

    ​ 将并发变成串行,牺牲执行效率,保证数据安全

    ​ from multiprocessing iport Lock

    ​ mutex = Loock()

    ​ mutex.acquire() # 加锁

    ​ mutux.release() # 修改数据

    18 队列

    1572007120267

    ​ FIFO队列:先进先出

    ​ from multiprocessing import Queue

    ​ q = Queue(5)

    ​ q.put() # 添加数据,若队列添加数据满了,则等待

    ​ q.put_nowait() # 添加数据,若队列添加数据满了,直接报错

    ​ # 获取队列中的数据

    ​ q.get() # 若队列中没有数据,会卡主等待

    ​ q.get_nowait() # 若队列中没有数据,会直接=报错

    19 堆栈

    LIFO

    20 IPC进程间通信

    ​ —进程间数据是隔离的

    ​ —队列可以让进程间通信

    ​ —把一个程序放入队列中,另一个程序从队列中获取,实现进程间数据交互

    21 生产者与消费者

    ​ 生产者:生产数据

    ​ 消费者:使用数据

    ​ 为了保证,供需平衡

    22 线程

    ​ —什么是线程

    ​ 进程:资源单位

    ​ 线程:执行单位

    ​ —创建进程时,会自带一个线程

    ​ 一个进程下可以创建多个线程

    ​ —使用线程的好处

    ​ 节省资源的开销

    ​ — 进程与线程优缺点:
    ​ —进程:

    ​ 优点:

    ​ —多核下可以并行执行

    ​ —计算密集型下提高效率

    ​ 缺点:

    ​ —开销资源远高于线程

    ​ —线程:
    ​ 优点:

    ​ —占用资源远比进程小

    ​ —io密集型下提高效率

    ​ 缺点:

    ​ —无法利用多核优势

    23 线程间数据是共享的

    ​ —画图

    24 GIL全局解释器锁

    1572007172487

    ​ —只有cpython才有自带一个GIL全局解释器锁

    ​ 1 GIL本质上就是一个互斥锁

    ​ 2 GIL为了阻止同一个进程内多个线程同时执行(并行)

    ​ —单个进程下的多线程无法实现并行,但能实现并发

    ​ 3 这把锁主要是因为cpython的内存管理不是“线程安全”的

    ​ —内存管理

    ​ —垃圾回收机制

    ​ 注意:多个线程过来执行,一旦遇到io操作,机会立马释放GIL解释器锁,交给下一个先进来的线程

    ​ 总结:GIL存在的目的就是为了保证线程阿安全的,保证数据安全

    25 多线程使用的好处

    ​ —多线程:
    ​ io密集型,提高效率

    ​ —多进程

    ​ 计算密集型,提高效率

    26 死锁现象(了解)

    1572007200046

    画图

    27 递归锁(了解)

    解决死锁现象
    mutex = Lock()  # 只能引用1次
    mutex1, mutex2 = RLock()  # 可以引用多次
    +1, 只要这把锁计数为0释放该锁, 让下一个人使用, 就不会出现死锁现象.
    

    28 信号量

    ​ 信号量也是一把锁,可以让多个任务一起使用

    ​ 互斥锁:

    ​ 只能让一个任务使用

    ​ 信号量:

    ​ 可以让多个任务一起使用

    ​ sm = Semaphore(5) 可以让5个任务使用

    29 线程队列

    ​ 使用场景:
    ​ 若线程间数据不安全情况下使用线程队列,为了保证线程间数据的安全

    ​ import queue

    ​ —FIFO:先进先出队列

    ​ queue.Queue()

    ​ —LIFO:后进先出队列

    ​ —根据数字大小判断,判断出队友的优先级

    ​ —队列数据是无序的

    ​ queue.priorityQueue()

    30.event事件

    ​ 可以控制线程的执行,让一些线程控制另一些线程的执行.
    ​ e = Event()

    - 线程1
    e.set()  # 给线程2发送信号,让他执行
    
    - 线程2
    e.wait()  # 等待线程1的信号
    

    31.进程池与线程池

    ​ 为了控制进程/线程创建的数量,保证了硬件能正常运行.
    ​ from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor

    pool1 = ProcessPoolExecutor()  # 默认CPU个数
    pool2 = ThreadPoolExecutor()  # CPU个数 * 5
    pool3 = ProcessPoolExecutor(100)  # 100个
    pool4 = ThreadPoolExecutor(200)  # 200个
    
    # 将函数地址的执行结果,给回调函数
    pool4.submit(函数地址, 参数).add_done_callback(回调函数地址)
    
    - 回调函数(必须接收一个参数res):
        # 获取值
        res2 = res.result()
    

    32.协程

    - 进程: 资源单位
        - 线程: 执行单位
        - 协程: 单线程下实现并发, 不是任何的单位,是程序员YY出来的名字.
    
    - 单线程下实现并发
        好处是节省资源, 单线程 < 多线程 < 多进程
    
        - IO密集型下:
            协程有优势
    
        - 计算密集型下:
            进程有优势
    
    - 高并发:
        - 多进程 + 多线程 + 协程   (Nginx)
    
    协程的创建:
        手动实现切换 + 保存状态:
            - yield
    
            - 函数一直在调用next()
                会不停地切换
    
            yield不能监听IO操作的任务
            - gevent来实现监听IO操作
    

    33.gevent
    pip3 install gevent
    from gevent import monkey
    monkey.patch_all() # 设置监听所有IO
    from gevent import spawn, joinall # 实现 切换 + 保存状态

    - 实现了单线程下实现并发
    s1 = spawn(任务1)
    s2 = spawn(任务2)
    joinall([s1, s2])
    

    34.IO模型(了解)

    - 阻塞IO
        - 非阻塞IO
        - 多路复用IO
        - 异步IO			
    

  • 相关阅读:
    MariaDB · 版本特性 · MariaDB 的 GTID 介绍
    stm8s 中断重复进入
    PCB积累
    链表的创建、增加、删除、改数据、遍历
    百度文库文字下载工具指引
    防倒灌的开关电路
    AD快速从原理图查找pcb中元件
    三目运算符填坑
    嵌入式结构化分层思想
    原码,反码,补码
  • 原文地址:https://www.cnblogs.com/1012zlb/p/11741137.html
Copyright © 2011-2022 走看看