zoukankan      html  css  js  c++  java
  • PYTHON2.day05

    1.poll方法实现IO多路复用
       p = poll()
       p.register()
       p.unregister()
       p.poll()
      
    2.epoll方法实现IO多路复用
       * 效率更高
       * 触发方式更多
       * 可以监控的更多IO
      
    3.struct模块
       功能:python数据转换为bytes发送
            
    Struct(fmt)生成数据格式对象
    pack()  将数据打包转换为bytes
    unpack()  将bytes数据解析


    4.本地套接字
        用于本地两个进程之间进行数据通信
       
    5.多任务编程
    6.进程(process)
      
    *****************************************************************************************
    一.基于fork的多进程编程
        1.进程的运行特征
          【1】进程可以使用计算机的多核资源
          【2】进程是计算机分配资源的最小单位
          【3】进程之间互不影响,各自独立
          【4】每个进程拥有独立的空间,各自使用自己的空间
        2.fork 使用
          pid = os.fork()
          功能:创建新的进程

          没有参数
          返回值:整数 ,如果创建进程失败,返回负数
                               如果成功,则在原有进程中返回新进程的PID,在新进程中返回0
                        
          注意:*子进程会复制父进程的全部内存空间。从fork下一句开始执行
                * 父子进程各自独立运行,运行顺序不一定,进程执行不同的内容几乎是固定搭配
                *父子进程有各自特征比如
                *父进程fork之前开辟的空间,子进程同样拥有,父子进程对各自空间的操作,
                 不会相互影响
           

      1 import os
      2 from time import sleep
      3 
      4 pid = os.fork()
      5 
      6 if pid < 0:
      7     print("Creat pricess failed")
      8 elif pid == 0:
      9     sleep(2)
     10     print("The new process")
     11 else:
     12     sleep(3)
     13     print("The old process")
     14 
     15 print("fork test over")
    fork.py

    1    

    eg2:

    fock1

    eg3":

    fock2

      1 import os
      2 from time import sleep
      3 
      4 print("******************")
      5 a= 1
      6 
      7 
      8 pid = os.fork()
      9 
     10 if pid < 0:
     11     print("Creat process failed")
     12 elif pid == 0:
     13     print("Child process")
     14     print("a=%d"%a)
     15     a = 10000
     16 else:
     17     # sleep(1)
     18     print("Parent proess")
     19     print("a:",a)
     20 
     21 print("all a=%d"%a)
     22 
    fork2.py父子进程随机

    2019-02-20_8-23-46

      1 import os
      2 from time import sleep
      3 
      4 print("******************")
      5 a= 1
      6 
      7 
      8 pid = os.fork()
      9 
     10 if pid < 0:
     11     print("Creat process failed")
     12 elif pid == 0:
     13     print("Child process")
     14     print("a=%d"%a)
     15     a = 10000
     16 else:
     17     sleep(1)
     18     print("Parent proess")
     19     print("a:",a)
     20 
     21 print("all a=%d"%a)
     22 
    fork3.py

    父进程sleep(1),子进程在先

    2

    二.进程相关函数
         1.os.getpid()
           功能:获取一个进程的PID
           返回值:返回当前进程的PID

      1 import os
      2 from time import sleep
      3 
      4 pid = os.fork()
      5 
      6 if pid <0:
      7     print("Error")
      8 elif pid == 0:
      9     print("Child PID:",os.getpid())
     10 else:
     11     print("Parent PID:",os.getpid())
    getpid.py

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

      1 import os
      2 from time import sleep
      3 
      4 pid = os.fork()
      5 
      6 if pid <0:
      7     print("Error")
      8 elif pid == 0:
      9     print("Child PID:",os.getpid())
     10     print("GET parent pid:",os.getppid())#在子进程中获取父进程pid
     11 
     12 else:
     13     print("Parent PID:",os.getpid())
     14     print("Det child pid",pid)#在父进程中获取子进程pid
    getppid.py

    getppid           
         3.os._exit(status)
           功能:结束一个进程
           参数:标书进程的终止状态

      1 import os
      2 
      3 os._exit(0)#进程退出
      4 
      5 print("Process exit")
    exit.py

    exit
         4.sys.exit([status])   默认0
           功能:进程退出
           参数:整数   退出状态
                 字符串 表示退出时打印内容
      

      1 import os,sys
      2 
      3 
      4 sys.exit("退出进程")
      5 
      6 print("Process exit")
    sys_exit.py

    sys_exit   
        
    三.孤儿和僵尸
         1.孤儿进程:父进程先于子进程退出此时子进程成为孤儿进程
            * 孤儿进程会被系统进程收养,此时系统进程就会成为该进程新的父进程,
              孤儿进程退出该进程会自动处理

        2.僵尸进程:子进程先于父进程退出,父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程
            * 僵尸进程虽然结束但是会存留部分PCB在内存,大量僵尸进程会占用内存资源
         3.如何避免僵尸进程产生
           [1]:使用wait函数处理子进程退出
               pid,status = os.wait()

               功能:在父进程中阻塞等待处理子进程退出
               返回值:pid 退出的子进程的PID
                       status 子进程退出状态
               pid,status = os.Waitpid(pid,option)
               功能:在父进程中处理进程的进出状态I
               参数:pid -l 表示等待任意子进程退出
                          >0表示指定的子进程退出
                     option  0 表示阻塞等待
                             WHOHANG  表示非阻塞
               返回值:pid 退出的子进程的PID
                       status 子进程退出状态
          [2]创建二级子进程处理僵尸
               1.父进程创建爱你子进程等待回收子进程
               2.子进程创建二级子进程然后退出
               3.二级子进程成为孤儿,和原来的父进程一同执行事件
          [3]通过信号处理子进程退出
              原理:子进程退出时会发送信号给父进程,如果父进程忽略了子进程的信号,
                    系统就会自动处理子进程退出
              方法:
                   使用signal模块在父进程创建前写下如下语句
                  
                  import signal
                   signal.signal(signal.SIGCHLD,signal.SIG_ING)

              优点:*非阻塞不会影响父进程运行
                    *使用该方法父进程可以脱离所有子进程退出
     

      1 import os
      2 from time import sleep
      3 
      4 pid = os.fork()
      5 
      6 if pid ==0:
      7     print("Child PID:",os.getpid())
      8     os._exit(0)
      9 else:
     10     print("Parent process,...")
     11     while True:
     12         pass
    js.py

    jiangshi 

      1 import os
      2 from time import sleep
      3 
      4 pid = os.fork()
      5 
      6 if pid <0:
      7     print("Error")
      8 elif pid == 0:
      9     sleep(3)
     10     print("Child %d process exit"%os.getpid())
     11     os._exit(2)   #2*256 = status: 512
     12 
     13 else:
     14     pid,status = os.wait()
     15     print("pid:",pid)
     16 #print("status:",status)
     17     print("status:",os.WEXITSTATUS(status))
     18     while True:
     19         pass
    wait.py

    wait wait_2

      1 import os
      2 from time import sleep
      3 
      4 print("******************")
      5 a= 1
      6 
      7 
      8 pid = os.fork()
      9 
     10 if pid < 0:
     11     print("Creat process failed")
     12 elif pid == 0:
     13     print("Child process")
     14     print("a=%d"%a)
     15     a = 10000
     16 else:
     17     sleep(1)
     18     print("Parent proess")
     19     print("a:",a)
     20 
     21 print("all a=%d"%a)
    fork.py

    fork1 

      1 import os
      2 from time import sleep
      3 
      4 pid = os.fork()
      5 
      6 if pid <0:
      7     print("Error")
      8 elif pid == 0:
      9     sleep(3)
     10     print("Child %d process exit"%os.getpid())
     11     os._exit(2)   #2*256 = status: 512
     12 else:
     13     #非阻塞等待
     14     while True:
     15         p,status = os.waitpid(-1,os.WNOHANG)
     16         if p !=0:
     17             break
     18         sleep(2)
     19         sleep(1)
     20         print("做了其他事情")
     21     while True:
     22         print("完成父进程的其他事情")
     23         sleep(2)
    waitpid.py

    waitpid        

      1 #创建二级子进程处理僵尸
      2 import os
      3 from time import sleep
      4 
      5 def f1():
      6     sleep(3)
      7     print("元宵...")
      8 
      9 def f2():
     10     sleep(4)
     11     print("处理南北甜咸之争...")
     12 
     13 pid = os.fork()
     14 
     15 if pid <0:
     16     print("Error")
     17 elif pid ==0:
     18     p = os.fork()#创建二级子进程
     19     if p ==0:
     20         f2()#二级子进程做另一件事
     21     else:
     22         os._exit(0)
     23 else:
     24     os.wait()#等待子进程退出
     25     f1()
    child_child.py

    child_child

      1 import signal
      2 import os
      3 #处理子进程退出
      4 signal.signal(signal.SIGCHLD,signal.SIG_IGN)
      5 pid = os.fork()
      6 if pid < 0:
      7     print("Error")
      8 elif pid ==0:
      9     print("Child PID:",os.getpid())
     10 else:
     11     pass
     12     while True:
     13         pass
    signal.py

    signal

    群聊聊天室

    功能: 类似qq微信群聊

    1. 进群需要输入姓名,姓名不能重复
    2. 进入聊天室会向其他人发送通知 
         xxx 进入了聊天室
    3. 某人发消息群里其他人能够收到
         xxx说:xxxxxxxxxxxx
    4. 某人退出聊天室也会向其他人发通知
         xxx 退出了聊天室
    5. 管理员可以发送管理员消息,此时群里所有人都能收到
         管理员说:xxxxxxxx
    (服务器可以向所有的用户发送)


    1. 确定技术模型
        -使用字典保存用户信息{name:ip}
        - 消息发送:客户端--》服务端--》其他客户端
        - 套接字:udp套接字
        * 存储用户:字典或者列表
        - 消息收发随意:使用两个(多)进程分别处理消息收发
         

    2. 注意事项
        * 设计封装方法                       将每个功能封装为函数
        * 写一个模块测试一个函数             实现一个功能,测试一个功能
        * 注释的编写添加                    
        * 流程                               搭建网络连接,逐个功能实现                              
              
              
    具体实现功能

       1. 搭建网络连接
            服务端 : 创建UDP套接字,绑定地址,创建多进程

           客户端 : 创建UDP套接字,创建多0进程

       2. 用户登录
            服务端 : *  接收姓名
                      * 判断姓名是否存在
                      * 根据判断结果回复客户端
                      * 不允许登录则功能结束
                      * 允许登录将用户则加入数据结构
                      * 将用户登录提示发送给其他人


            客户端 : * 输入姓名
                      * 将姓名发送给服务器
                      * 接收服务器反馈 ,如果不允许登录则重新输入,允许则进入聊天
                      * 创建新的进程,用于消息收发


        3. 聊天
         服务端:     * 接收消息,判断请求类型
                      * 将消息转发给其用户

        客户端:     * 循环发送消息
                      * 循环接收消息

       4. 用户退出
         服务端 : * 收到q表示客户端退出
                   * 将用户从user移除
               * 告知其他人xxx退出,给该用户发送退   出指令

        客户端 : * 输入q表示退出
                   * 将退出信息发送给服务器
               * 发送进程退出
               * 接收进程接收到服务器指令退出

       5. 管理员消息

      1 #coding=utf-8
      2 '''
      3 Chatroom
      4 env:python3.5
      5 exc:socket and fork
      6 '''
      7 from socket import *
      8 import os,sys
      9 
     10 #用于存储用户{name:addr}
     11 user ={}
     12 
     13 #处理登录
     14 def do_login(s,name,addr):
     15     #判断姓名是否存在
     16     if name in user:
     17         s.sendto("该用户已存在".encode(),addr)
     18         return
     19     s.sendto(b'OK',addr)
     20 
     21     #先通知其他人
     22     msg = "欢迎%s 进入聊天室"%name
     23     for i in user:
     24         s.sendto(msg.encode(),user[i])#user[i]发送,通过键取值
     25     #将用户插入user
     26     user[name] = addr
     27 
     28 
     29 def do_chat(s,name,text):
     30     msg ="%s : %s"%(name,text)#格式
     31     #循环发送给所有人,除了自己
     32     for i in user:
     33         if i != name:
     34             s.sendto(msg.encode(),user[i])#接受UDP消息,user[i]发送,通过键取值
     35 
     36 
     37 
     38 def do_requests(s):
     39     while True:
     40         data,addr = s.recvfrom(1024)#接收UDP消息
     41         #解析请求
     42         msgList = data.decode().split(' ')#*spilt('.')方法将指定的分隔符进行拆分,拆分将会组成一个字符串的数组并返回
     43         #区分请求类型
     44         if msgList[0]=='L':
     45             do_login(s,msgList[1],addr)
     46         elif msgList[0] =='C':
     47             #重新组织消息内容
     48             text = ' '.join(msgList[2:])
     49             do_chat(s,msgList[1],text)
     50         elif msgList[0] == 'Q':
     51             do_quit(s,user,msgList[1])
     52 
     53 def do_quit(s,user,name):
     54     msg = "
    %s 退出了聊天室"%name
     55     for i in user:
     56         if i == name:
     57             s.sendto(b'quit',user[i])
     58         else:
     59             s.sendto(msg.encode(),user[i])
     60     #删除该用户
     61     del user[name]
     62 
     63 #创建网络连接
     64 def main():
     65     ADDR = ('0.0.0.0',8888)
     66     #创建套接字
     67     s = socket(AF_INET,SOCK_DGRAM)#创建数据报套接字
     68     s.bind(ADDR)#绑定地址
     69 
     70     #处理各种客户端请求
     71     do_requests(s)
     72 
     73 if __name__=="__main__":
     74     main()
    chart_server.py
      1 from socket import *
      2 import os,sys
      3 
      4 #服务区的地址
      5 ADDR = ('172.40.71.149',8888)
      6 
      7 #发送消息
      8 def send_msg(s,name):#发消息
      9     #输入q表示退出聊天室
     10     while True:
     11         text = input("发言:")
     12         if text =="q":
     13             msg = 'Q ' + name
     14             s.sendto(msg.encode(),ADDR)
     15             sys.exit("退出聊天室")
     16         msg = "C %s %s"%(name,text)#C
     17         s.sendto(msg.encode(),ADDR)
     18 
     19 
     20 def recv_msg(s):#收消息
     21     while True:
     22         data,addr = s.recvfrom(2048)
     23         #服务器发来quit表示要退出
     24         if data.decode()=="quit":
     25             sys.exit(0)
     26         print(data.decode(),"
    发言:",end="")
     27 
     28 #创建网络连接
     29 def main():
     30     s = socket(AF_INET,SOCK_DGRAM)
     31     while True:
     32         name = input("请输入姓名:")
     33         msg = "L "+name
     34         s.sendto(msg.encode(),ADDR)#发送请求给服务端
     35         #等待回应
     36         data,addr = s.recvfrom(1024)#消息收发
     37         if data.decode() =="OK":
     38             print("您已经进入聊天室")
     39             break
     40         else:
     41             print(data.decode())#打印不允许的原因
     42 
     43     #创建新的进程,用以消息收发的随意性
     44     pid = os.fork()#创建新的进程
     45     if pid < 0:
     46         sys.exit("error创建进程失败!!")
     47     elif pid == 0:
     48         send_msg(s,name)#发送消息
     49     else:
     50         recv_msg(s)#接受消息
     51 
     52 
     53 if __name__=="__main__":
     54     main()
    chart_clent.py

    聊天室
    作业: 1. 完成退出功能,解决格式问题
               聊天过程中输入quit表示退出
            2. 整理fork创建进程内容
            3. 用fork创建父子进程,同时复制一个文件,各复制一半到一个新的文件中

  • 相关阅读:
    SqlBulkCopy类进行大数据(10000万条以上)插入测试
    win7 64位下android开发环境的搭建
    Linq语法详细
    理解ASP.NET MVC中的ActionResult
    webBrowser 模拟登录
    C#中的WebBrowser控件的使用
    httpwebrequest详解【转】
    Post方式调用wcf服务
    EXTJS4.2 控件之Grid getRowClass 添加行背景色
    SQL 跨服务器数据库增、删、改、查(二)
  • 原文地址:https://www.cnblogs.com/shengjia/p/10404493.html
Copyright © 2011-2022 走看看