zoukankan      html  css  js  c++  java
  • 网络编程与进程

    # 软件开发架构:
    
    ​```
    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
    
    ​```
    
    
    
  • 相关阅读:
    tomcat监控
    rsync排除文件同步
    [转载]centos7 快速安装 mariadb(mysql)
    linux下的头文件和库文件搜索路径 (转)
    用apt-get install一个软件的时候出现错误: 无法解析或打开软件包的列表或是状态文件
    模拟一个简单的基于tcp的远程关机程序(转)
    TCP连接的建立以及利用tcpdump分析连接建立的过程(转)
    UNIX网络编程(转载)
    开源代码网站(转)
    学了5天Arm,今天谈谈初学感受 (转)
  • 原文地址:https://www.cnblogs.com/jinhongquan/p/11752182.html
Copyright © 2011-2022 走看看