网络编程 与 并发编程 汇总

软件开发架构:

C/S:
    Client: 客户端
    Server: 服务端

    优点:
        占用网络资源少,软件的使用稳定

    缺点:
        服务端更新后,客户端也得跟着跟新.
        需要使用多个软件,需要下载多个客户端

B/S:
    Browser: 浏览器(客户端)
    Server: 服务端

服务端与客户端作用:
    服务端: 24小时不间断提供服务
    客户端: 需要体验服务端时,再去连接服务端,并享受服务

一 网络编程:
1.互联网协议OSI七层协议
    1)应用层
    2)表示层
    3)会话层
    4)传输层
    5)网络层
    6)数据链路层
    7)物理连接层

    - 物理连接层
        基于电信号发送二进制数据.

    - 数据链路层
        1) 规定好电信号的分组方式
        2) 必须要有一块网卡:
            - mac地址:
                12位唯一的16进制字符串
                    - 前6位: 厂商号
                    - 后6位: 流水号
        - 以太网协议:
            在同一个局域网内通信.
            - 单播
                1对1吼
            - 广播
                多对多吼
                - 广播风暴:
                - 不能跨局域网通信

    - 网络层
        - ip: 定位局域网的位置
        - port: 唯一标识一台计算机上一个应用程序.
        - arp协议:
            将mac地址获取,并解析成ip和port.

    - 传输层
        - TCP
            特点:
                TCP协议称之为流式协议.

            若想要通信,必须建立连接,并建立双向通道.
            - 三次握手,四次挥手
                - 三次握手建连接
                    - 客户端往服务端发送请求建立通道
                    - 服务端要确认客户端的请求,并往客户端也发送请求建立通道
                    - 客户端接收到服务端建立连接的请求,并返回确认
                    - 建立双向通道

                - 双向通道:
                    - 反馈机制
                    客户端往服务端发送请求获取数据,服务端务必返回数据,客户端确认收到.
                    反则会反复发送,一直到某个时间段内,会停止发送

                - 四次挥手断连接
                    - C往S发送断开连接请求,S返回确认收到
                    - S需要再次发送断开连接请求
                    - C返回确认收到
                    - 最终确认断开连接

        - UDP
            1)数据不安全
            2)不需要建立双向通道
            3)传输速度快
            4)不会有粘包问题
            5)客户端发送数据,不需要服务端确认收到,爱收不收

        TCP与UPD的区别:
            TCP: 比喻成在打电话
            UDP: 比喻成发送短信

    - 应用层
        - ftp
        - http:
            可以携带一堆数据

        - http + ssl

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

3.手撸socket套接字模板
    - 服务端:
        import socket
        server = socket.socket()
        server.bind(
            (ip, port)
        )  # 绑定手机号
        server.listen(6)  # 半连接池: 可以接待7个客户端
        # 监听连接
        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 = 'gagawagwaga'
    # 打包成报头
    headers = struct.pack('i', len(data))

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

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

    升级版:
        先将数据存放到字典中,将字典打包发送过去
        - 字典的好处:
            - 真实数据长度
            - 文件的描述信息
            - 发送的数据,更小

            dic = {
                'data_len': 1000000000000000000000046546544444444444444444444444444444444444444,
                文件的描述信息
            }

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', 9527)
            )
            server.listen(5)  ---

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

        # 必须重写父类的handle, 当客户端连接时会调用该方法
        def handle(self):
            print(self.client_address)
            while True:
                try:
                    # 1.接收消息
                    # 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 as 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份时间片,分配给每一个进程.

        - 分级反馈队列
            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 import Lock
    mutex = Lock()
    # 加锁
    mutex.acquire()
    修改数据
    mutex.release()

18.队列
    - 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全局解释器锁

    - 只有Cpython才有自带一个GIL全局解释器锁
    1.GIL本质上是一个互斥锁.
    2.GIL的为了阻止同一个进程内多个线程同时执行(并行)
        - 单个进程下的多个线程无法实现并行,但能实现并发

    3.这把锁主要是因为CPython的内存管理不是 "线程安全" 的.
        - 内存管理
            - 垃圾回收机制

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

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

25.多线程使用的好处
    - 多线程:
        IO密集型,提高效率

    - 多进程
        计算密集型,提高效率

26.死锁现象(了解)

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

28.信号量(绝对了解)
    信号量也是一把锁, 可以让多个任务一起使用.
    互斥锁:
        只能让一个任务使用
    信号量:
        可以让多个任务一起使用.
        sm = Semaphore(5)  可以让5个任务使用

29.线程队列
    使用场景:
        若线程间数据不安全情况下使用线程队列, 为了保证线程间数据的安全.
    import queue
    - FIFO: 先进先出队列
        queue.Queue()
    - LIFO: 后进先出队列
        queue.LifoQueue()
    - 优先级队列:
        - 根据数字大小判断,判断出队优先级.
        - 进队数据是无序的
        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
原文地址:https://www.cnblogs.com/whkzm/p/11740624.html