zoukankan      html  css  js  c++  java
  • Python网络编程(子进程的创建与处理、简单群聊工具)

    前言:
    昨天我们已经了解了多进程的原理以及它的实际使用

    Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,

    但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

    子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,

    父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

    Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程

    既然是进程那么就会有运行和退出
    接下来我们就来了解一下进程的退出以及处理
     
    孤儿进程:
        当父进程于子进程退出,此时子进程就会成为孤儿进程
        特征:
             孤儿进程会被系统指定进程收养,即系统进程成为
     这个孤儿进程新的父进程,系统进程会自动处理进程退出状态
     
    僵尸进程:
        当子进程于父进程退出父进程没处理子进程的退出状态
        此时子进程就会成为僵尸进程
        僵尸进程会滞留部分PCB信息在内存中,大量的僵尸进程会消耗系统给的内存资源
        所以要尽量避免僵尸进程的产生
     
    如何避免僵尸进程的产生:
        1.父进程先退出
        2.父进程处理子进程状态
     
        PID,status = os.wait
          功能:
             在父进程中阻塞等待处理子进程的退出
          返回值:
               pid :退出的那个子进程PID
       status :子进程的退出状态
          获取原来的退出状态:
                 wait(status)
          pid,status = os.waitpid(pid,option)
              功能:在父进程阻塞等待处理子进程的退出
              参数 :
                        pid   -1 表示等待任意子进程退出 
                                >0 表示等待对应PID号的子进程退出 option 
                                   0 表示阻塞等待 WNOHANG 表示非阻塞 
              返回值:pid 
                            退出的那个子进程的PID号 status 子进程的退出状态 
     
     
    创建二级子进程
    • 父进程创建子进程等待进程退出
    • 子进程创建下一个进程,然后立即退出
    • 二级子进程成为孤儿进程  处理具体工作
     
     
    multiprocessing  模块创建进程
      1.需要将要做的事情封装为函数
      2.使用multiprocessing提供的process 创建进程对象
      3.通过进程对象和process初始化进程进行进程的设置绑定函数
      4.启动进程,会自动执行绑定的函数
      5.完成进程的回收
     
    创建进程对象:
       process()
         功能:
           创建进程对象
         参数:
           target函数对象
           name 进程称()
           args元组 用来给target函数位置传参
           kwargs字典 用来给target函数键值传参
       p.start()
         功能:
           启动进程自动运行terget绑定函数,
           此时进程被创建
       p.join([timeout])
         功能:
           等待阻塞子进程退出
         参数:超时检测
         如果不使用join回收可能产生僵尸进程
     
    • 使用multiprocessing创建进程子进程同样复制父进程的全部内存空间
    • 之后自己的独立空间 执行互不干扰 子进程也有自己的PID特有资源等
    • 使用multiprocessing创建子进程,一般父进程功能就是创建子进程
    • 回收子进程返回事件交给子进程完成
     
     
     
     
     
     
    简单群聊:
     
    功能:
      类似QQ群聊
      1.进入聊天室需要输入姓名 姓名不能重复
      2.有人进入聊天室会向其他人发起通知  xxx进入聊天室
      3.如果一个人发消息则其他人都能收到  xxx说:...
      4.如果某个人退出聊天室也会收到通知  xxx退出聊天室
      5.服务端可以喊话:此时群里所有的都能收到服务端消息  管理员说:...
     
     
    服务器端:

    from socket import * 
    import os, sys
    
    
    # 发送管理员消息
    def do_child(s, addr):
        while True:
            msg = input("管理员消息:")
            msg = "C 管理员 " + msg
            s.sendto(msg.encode(), addr)
    
    
    # 用户登录
    def do_login(s, user, name, addr):
        if (name in user) or name == "管理员":
            s.sendto("该用户已存在".encode(), addr)
            return
        s.sendto(b'OK', addr)
        # 通知所有人
        msg = "
    欢迎 %s 进入聊天室" % name
        for i in user:
            s.sendto(msg.encode(), user[i])
        # 插入user
        user[name] = addr
    
    
    def do_chat(s, user, name, data):
        msg = "
    {} 说: {}".format(name, data)
        for i in user:
            if i != name:
                s.sendto(msg.encode(), user[i])
    
    
    def do_quit(s, user, name):
        msg = "
    %s 离开了聊天室" % name
        for i in user:
            if i == name:
                s.sendto(b'EXIT', user[i])
            else:
                s.sendto(msg.encode(), user[i])
        del user[name]  # 删除离开的用户
    
    
    # 接收客户端请求并处理
    def do_parent(s):
        # 用于存储用户 {'Alex':('127.0.0.1',8888)}
        user = {}
        while True:
            msg, addr = s.recvfrom(1024)
            msgList = msg.decode().split(' ')
            if msgList[0] == 'L':
                do_login(s, user, msgList[1], addr)
            elif msgList[0] == 'C':
                # "C Levi [I miss you]"
                data = ' '.join(msgList[2:])
                do_chat(s, user, msgList[1], data)
            elif msgList[0] == 'Q':
                do_quit(s, user, msgList[1])
    
    
    # 创建套接字,网络连接,创建父子进程
    def main():
        # server address
        ADDR = ('0.0.0.0', 8888)
        # 创建套接字
        s = socket(AF_INET, SOCK_DGRAM)
        s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        s.bind(ADDR)
    
        # 创建父子进程
        pid = os.fork()
        if pid < 0:
            sys.exit("创建进程失败")
        elif pid == 0:
            do_child(s, ADDR)
        else:
            do_parent(s)
    
    if __name__ == "__main__":
        main()


    客户端:

    from socket import * 
    import sys, os
    
    
    def login(s, ADDR):
        while True:
            name = input("请输入用户名:")
            msg = "L " + name
            s.sendto(msg.encode(), ADDR)
            # 接收登录结果
            data, addr = s.recvfrom(1024)
            if data.decode() == 'OK':
                print("@进入聊天室@")
                return name
            else:
                print(data.decode())
    
    
    # 发送消息
    def do_child(s, name, addr):
        while True:
            text = input("发言(quit退出):")
            # 退出
            if text.strip() == "quit":
                msg = "Q " + name
                s.sendto(msg.encode(), addr)
                sys.exit("退出聊天室")
    
            msg = "C %s %s" % (name, text)
            s.sendto(msg.encode(), addr)
    
    
    # 接收消息
    def do_parent(s):
        while True:
            msg, addr = s.recvfrom(1024)
            if msg.decode() == 'EXIT':
                sys.exit(0)
            print(msg.decode() + "
    发言(quit退出):",end="")
    
    
    # main控制套接字的创建
    def main():
        if len(sys.argv) < 3:
            print("argv is error")
            return
        HOST = sys.argv[1]
        PORT = int(sys.argv[2])
        ADDR = (HOST, PORT)
    
        s = socket(AF_INET, SOCK_DGRAM)
    
        name = login(s, ADDR)
        if name:
            pid = os.fork()
            if pid < 0:
                sys.exit("创建子进程失败")
            elif pid == 0:
                do_child(s, name, ADDR)
            else:
                do_parent(s)
        else:
            return
    
    
    if __name__ == "__main__":
        main()
  • 相关阅读:
    python鸭子类型
    chrome Network 过滤和高级过滤
    代理服务器支持https(转)
    解决fiddler不能抓取firefox浏览器包的问题(转)
    Fiddler抓包8-打断点(bpu)(转)
    Git diff (---和+++具体解释)(转)
    Xposed模块编写
    Android 渗透测试学习手册(八)ARM 利用
    Android 渗透测试学习手册(七)不太知名的 Android 漏洞
    Android 渗透测试学习手册(六)玩转 SQLite
  • 原文地址:https://www.cnblogs.com/ParisGabriel/p/9458056.html
Copyright © 2011-2022 走看看