博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PYTHON2.day05
阅读量:5897 次
发布时间:2019-06-19

本文共 9549 字,大约阅读时间需要 31 分钟。

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

    

eg2:

eg3":

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父子进程随机

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),子进程在先

 

二.进程相关函数

     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

     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

           

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

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

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

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

   

    
三.孤儿和僵尸
     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

 

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

 

 

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

 

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

        

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

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

 

群聊聊天室

功能: 类似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 = "\n%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(),"\n发言:",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创建父子进程,同时复制一个文件,各复制一半到一个新的文件中

转载于:https://www.cnblogs.com/shengjia/p/10404493.html

你可能感兴趣的文章
Aop RealProxy 千年遇BUG
查看>>
java解析虾米音乐
查看>>
rails将类常量重构到数据库对应的表中之三
查看>>
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
查看>>
android本地音乐播放器
查看>>
泛函编程(37)-泛函Stream IO:通用的IO处理过程-Free Process
查看>>
mysql 多行合并函数
查看>>
【案例】RAID卡写策略改变引发的问题
查看>>
Object.toString
查看>>
[Django学习]如何得到一个App
查看>>
Redis入门-1-数据模型List
查看>>
sparkStreaming+sql点击前十商品
查看>>
第四十八讲:tapestry 与 淘宝kissy editor编辑器带图片上传
查看>>
图像处理入门——扭曲
查看>>
nodejs核心编程笔记
查看>>
浅谈MySql的存储引擎(表类型)
查看>>
细节决定成败----Android应用程序的优化(二)
查看>>
正则表达式30分钟入门教程
查看>>
finsh indexMain
查看>>
Struts2国际化
查看>>