• 第九篇:网络编程补充与进程


    本篇内容

    1. udp协议套接字
    2. 开启进程的方式
    3. 多进程实现并发的套接字通信
    4. join方法
    5. 守护进程
    6. 同步锁
    7. 进程队列
    8. 生产者消费者模型
    9. 进程池
    10. paramiko模块

    一、 udp协议套接字

    1.TCP和UDP在传输层区别:
    UDP是无连接不可靠的数据报协议。TCP提供面向连接的可靠字节流。

    2.使用UDP常见应用:
    DNS(域名系统),NFS(网络文件系统),SNMP(简单网络管理协议)。

    3.代码应用:

    服务端:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    import socketserver
    class MyUDPhandler(socketserver.BaseRequestHandler):
        def handle(self):
            print(self.request)
            self.request[1].sendto(self.request[0].upper(),self.client_address)
    
    if __name__ == '__main__':
        s = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPhandler)
        s.serve_forever()
    

     客户端:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from socket import *
    
    udp_client = socket(AF_INET,SOCK_DGRAM)
    
    while True:
        msg=input('>>: ').strip()
        udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
        data,server_addr = udp_client.recvfrom(1024)
        print(data.decode('utf-8'))
    

     注意:但这种方式并不能控制客户端的并发数量,并发数量达到一定数量后,服务端会down掉,解决办法后续会提供。

    二、开启进程的方式

    开启进程的方式分为两种:

    (1)利用模块开启进程:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process
    import time
    def work(name):
        print('task <%s> is runing' %name)
        time.sleep(2)
        print('task <%s> is done' % name)
    
    if __name__ == '__main__':
        p1 = Process(target=work,args=('xiaolan',))
        p2 = Process(target=work,args=('xiaohong',))
        p1.start()
        p2.start()
        print('主程序')
    

     (2)利用类开启进程:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process
    import time
    
    class MyProcess(Process):
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('task <%s> is runing' % self.name)
            time.sleep(2)
            print('task <%s> is done' % self.name)
    
    if __name__ == '__main__':
        p = MyProcess('xiaolan')
        p.start()
        print('主程序')
    

    三、多进程实现并发的套接字通信

    基于刚刚学习的开启进程的方式,咱们就用进程的方式来开启一个网络通信。

    服务端:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process
    from socket import *
    
    s = socket(AF_INET,SOCK_STREAM)
    s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    def talK(conn,addr):
        while True:
            try:
                data=conn.recv(1024)
                if not data:break
                conn.send(data.upper())
            except Exception:
                break
        conn.close()
    
    if __name__ == '__main__':
        while True:
            conn,addr = s.accept()
            p=Process(target=talK,args=(conn,addr))
            p.start()
    
        s.close()
    

     客户端:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from socket import *
    
    c = socket(AF_INET,SOCK_STREAM)
    c.connect(('127.0.0.1',8080))
    
    while True:
        msg = input('>>: ').strip()
        if not msg:continue
        c.send(msg.encode('utf-8'))
        data = c.recv(1024)
        print(data.decode('utf-8'))
    
    c.close()
    

    四、join方法

    1.定义:

    (1)join方法的作用是阻塞主进程(挡住,无法执行join以后的语句),专注执行多进程。

    (2)多进程多join的情况下,依次执行各进程的join方法,前头一个结束了才能执行后面一个。

    (3)无参数,则等待到该进程结束,才开始执行下一个进程的join。

     2.代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process
    import time
    
    def work(name):
        print('task <%s> is runing' %name)
        time.sleep(3)
        print('task <%s> is done' % name)
    
    if __name__ == '__main__':
        p1 = Process(target=work,args=('xiaolan',))
        p2 = Process(target=work,args=('xiaohong',))
        p3 = Process(target=work,args=('xiaolv',))
    
        p_list = [p1, p2, p3]
        for p in p_list:
            p.start()
        for p in p_list:
            p.join()
        print('主进程')
    

    五、守护进程

    1.定义:

    (1)守护进程是主程序创建的。

    (2)守护进程会在主进程代码执行结束后就终止。

    (3)守护进程内无法再开启子进程,否则抛出异常:

    AssertionError: daemonic processes are not allowed to have children。

    2.代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process
    import time
    
    def work(name):
        print('task <%s> is runing' %name)
        time.sleep(2)
        print('task <%s> is done' % name)
    
    if __name__ == '__main__':
        p1 = Process(target=work,args=('xiaolan',))
        p1.daemon = True
        p1.start()
        print('主程序')
    

    六、同步锁

    1.定义:

    通常被用来实现共享资源的同步访问,为每一个共享资源创建一个Lock对象当你需要访问该资源时,调用qcuqire方法来获取锁对象(如果其他线程已经获得该锁,则当前线程需等待期被释放),待资源访问完后,在调用release方法释放锁。

    2.代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process,Lock
    import time
    def work(name,mutex):
        mutex.acquire()
        print('task <%s> is runing' %name)
        time.sleep(2)
        print('task <%s> is done' % name)
        mutex.release()
    
    if __name__ == '__main__':
        mutex = Lock()
        p1 = Process(target=work,args=('xiaolan',mutex))
        p2 = Process(target=work,args=('xiaohong',mutex))
        p1.start()
        p2.start()
        print('主程序')
    

     3.代码应用:

    模拟抢票过程

    python代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    import json
    import os
    import time
    from multiprocessing import Process,Lock
    
    def search():
        dic = json.load(open('db.txt'))
        print('33[32m[%s] 看到剩余票数<%s>33[0m' %(os.getpid(),dic['count']))
    
    def get_ticket():
        dic = json.load(open('db.txt'))
        time.sleep(0.5) #模拟读数据库的网络延迟
        if dic['count'] > 0:
            dic['count'] -= 1
            time.sleep(0.5)  # 模拟写数据库的网络延迟
            json.dump(dic,open('db.txt','w'))
            print('33[31m%s 购票成功33[0m' %os.getpid())
    
    def task(mutex):
        search()
        mutex.acquire()
        get_ticket()
        mutex.release()
    
    if __name__ == '__main__':
        mutex = Lock()
        for i in range(10):
            p = Process(target=task,args=(mutex,))
            p.start()
    

     db.txt文件:

    {"count": 0}
    

     4.缺点:

    (1)运行效率低

    (2)需要自己加锁处理,操作繁琐

    七、进程队列

    1.定义:

    (1)Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。

    (2)maxsize是队列中允许最大项数,省略则无大小限制。

    2.代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Queue
    
    q = Queue(3)
    
    q.put('first')
    q.put('second')
    q.put('third')
    
    print(q.get())
    print(q.get())
    print(q.get())
    

    八、生产者消费者模型

    1.定义:

    在工作中,大家可能会碰到这样一种情况:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模式。

    2.优点:

    (1)解耦。

    (2)支持并发。

    (3)支持忙闲不均。

    3.代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Process, JoinableQueue
    import time, os
    
    def producer(q, name):
        for i in range(3):
            time.sleep(1)
            res = '%s%s' % (name, i)
            q.put(res)
            print('33[45m<%s> 生产了 [%s]33[0m' % (os.getpid(), res))
        q.join()
    
    def consumer(q):
        while True:
            res = q.get()
            time.sleep(1.5)
            print('33[34m<%s> 吃了 [%s]33[0m' % (os.getpid(), res))
            q.task_done()
    
    if __name__ == '__main__':
        q = JoinableQueue()
        p1 = Process(target=producer, args=(q, '红烧肉'))
        p2 = Process(target=producer, args=(q, '鱼香肉丝'))
        p3 = Process(target=producer, args=(q, '锅包肉'))
        c1 = Process(target=consumer, args=(q,))
        c2 = Process(target=consumer, args=(q,))
        c1.daemon = True
        c2.daemon = True
        p1.start()
        p2.start()
        p3.start()
        c1.start()
        c2.start()
        p1.join()
        print('主程序')
    

    九、进程池

    1.定义:

    Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

    2.代码:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    from multiprocessing import Pool
    import os
    import time
    
    def work(n):
        print('task <%s> is runing' % os.getpid())
        time.sleep(2)
        return n**2
    
    if __name__ == '__main__':
        p = Pool(4)
        res_l = []
        for i in range(10):
            res = p.apply_async(work,args=(i,))
            res_l.append(res)
        p.close()
        p.join()
    

     3.进程池之回调函数:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    import requests
    import os,time
    from multiprocessing import Pool
    
    def get_page(url):
        print('<%s> get :%s' % (os.getpid(), url))
        respone = requests.get(url)
        if respone.status_code == 200:
            return {'url': url,'text': respone.text}
    
    def parse_page(dic):
        print('<%s> parse :%s' % (os.getpid(), dic['url']))
        time.sleep(0.5)
        res = 'url:%s size:%s
    ' % (dic['url'], len(dic['text']))
        with open('db.txt', 'a') as f:
            f.write(res)
    
    if __name__ == '__main__':
        p = Pool(4)
        urls = [
            'https://www.baidu.com',
            'https://www.qq.com',
            'https://www.163.com',
            'https://www.sina.com',
            'https://www.jd.com',
            'https://www.taobao.com',
            'https://www.sohu.com',
        ]
    
        for url in urls:
            p.apply_async(get_page, args=(url,), callback=parse_page)
        p.close()
        p.join()
        print('主进程pid:', os.getpid())
    

    十、paramiko模块

    1.定义:

    paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。

    由于使用的是python这样的能够跨平台运行的语言,所以所有python支持的平台,如Linux, Solaris, BSD, MacOS X, Windows等,paramiko都可以支持,因此,如果需要使用SSH从一个平台连接到另外一个平台,进行一系列的操作时,paramiko是最佳工具之一。

    2.安装:

    由于paramiko是第三方模块,所以是需要我们单独安装的。

    pip3 install paramiko
    

     3.代码:

    (1)使用密码连接的方式:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    import paramiko
    
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname='192.168.0.1', port=22, username='root', password='root123456')
    
    stdin, stdout, stderr = ssh.exec_command('df -h')
    result = stdout.read()
    print(result.decode('utf-8'))
    ssh.close()
    

     (2)使用秘钥连接的方式:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    import paramiko
    
    private_key = paramiko.RSAKey.from_private_key_file('id_rsa')
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname='192.168.0.1', port=22, username='root', pkey=private_key)
    
    stdin, stdout, stderr = ssh.exec_command('df')
    result = stdout.read()
    print(result.decode('utf-8'))
    ssh.close()
    

     (3)上传或下载文件:

    #!/usr/binl/env python
    #encoding: utf-8
    #author: YangLei
    
    import paramiko
    
    transport = paramiko.Transport(('192.168.0.1', 22))
    transport.connect(username='root', password='root123456')
    
    sftp = paramiko.SFTPClient.from_transport(transport)
    sftp.put('test.txt', '/tmp/test.txt')
    sftp.get('/tmp/test.txt', 'test.txt')
    transport.close()
    
  • 相关阅读:
    [UWP 开发] 一个简单的Toast实现
    纯MarkDown博客阅读体验优化
    [沈航软工教学] 3、4班最终成绩排行榜
    [沈航软工教学] 期末附加作业
    [沈航软工教学] 前十三周3,4班排行榜
    [沈航软工教学] 前十二周3,4班排行榜
    [沈航软工教学] 前八周3,4班排行榜
    BugPhobia准备篇章:Beta阶段前后端接口文档
    BugPhobia回顾篇章:团队Alpha阶段工作分析
    BugPhobia贡献篇章:团队贡献分值与转会确定
  • 原文地址:https://www.cnblogs.com/00doudou00/p/7456658.html
Copyright © 2020-2023  润新知