zoukankan      html  css  js  c++  java
  • 网络编程(五)

    前情回顾

    本地套接字 : 本地进程间实现通信
    socket(AF_UNIX,SOCK_STREAM)

    进程 :一次执行的过程

    进程特征和概念
    PCB 虚拟内存 PID 父子进程 孤儿进程 僵尸进程

    ps -aux pa -ajx top nice renice

    进程的状态
    三态 五态


    fork()
    多程序 : 无法根据情况动态创建进程
    通过接口创建进程:便于控制,可以在程序运行中随时根据需要创建

    getpid getppid sys.exit os._exit

    处理僵尸进程
    1.让父进程先结束
    2.父进程处理子进程的退出
    wait waitpid
    处理信号

    3. 创建二级子进程
    ********************************************
    os.waitpid(pid,option)
    功能: 处理子进程的退出
    参数: pid : -1 表示等待任意的子进程退出
    >0 表示等待相应PID号的子进程
    option: 0 表示阻塞等待
    WNOHANG :表示非阻塞等待
    返回值: 同 wait
    os.waitpid(-1,0) ==== os.wait()

    创建二级子进程

    父进程创建子进程后等待子进程退出
    子进程创建二级子进程后马上退出,二级子进程成为孤儿
    让父进程和二级子进程处理具体事件


    群聊聊天室

    *选择使用什么样的套接字

    udp

    转发 客户端 ---》 服务器 ---》 其他客户端
    用print简单打印命令操作提示
    存储用户 列表 字典
    使用函数或者类来包装功能
    没完成一个功能检测一个功能


    *功能描述

    #类似于qq群聊 ,用户在加入聊天室时有一个简单的登录
    输入用户名即可
    实现 : 客户端输入用户名,发送给服务器,服务器存储

    #需要个数据结构保存用户
    收到发过来的用户名 放到列表或者字典中


    #当一个人发送消息 其他人可以接受消息
    张三 : xxxxxx
    实现 : 客户将消息发送给服务器,服务器遍历列表,进行转发

    #当一个人登录 退出时给其他人一些提示
    xxx login
    xxx logout
    实现:给服务器发送登录退出消息,服务器转发

    # 管理员发送消息 全部在线成员均可收到
    实现 : 服务端可控制消息发送,给所有人

    server:
    def login:
    def chat:

    def main()


    multiprocessing 模块创建进程 标准库

    1. 需要将事件封装为函数
    2. 使用multiprocessing提供的类创建新进程
    3. 新的进程和对应的函数相关联,进程启动会自动执行函数,完成事件
    4. 进程回收

    创建子进程类
    multiprocessing.Process()
    功能 : 创建子进程
    参数 : name : 给创建的进程起一个名字
    默认 process-1
    target : 目标函数
    args :元组 要给函数传递的参数 位置
    kwargs : 字典 要给函数传递的参数 键值

    进程对象属性函数
    p.start()
    功能 : 启动子进程 此时进程真正创建

    p.join([timeout])
    功能 : 阻塞等待回收相应的子进程
    参数 : 默认为阻塞,timeout为超时时间

    p的其他属性
    p.name 进程名称
    p.pid 创建的进程的PID号
    p.is_alive() 进程状态

    p.daemon
    默认值为False 表示主进程结束后 不影响子进程的执行
    如果设置为True 则主进程执行完毕所有的子进程一同退出

    * 设置必须在 start()前
    * 一般使用daemon = True时不用加join
    * 该属性并不是 linux/unix系统中所说的守护进程设置

    守护进程 : 生命周期长,随系统创建随系统销毁。
    不受前端控制,后台运行
    操作系统进程,或者是自动化运行进程居多

    作业 : 编写一个程序,使用multiprocessing
    要求创建两个进程来复制一个文件,各复制一半(以字节来分)

    下面是python程序
    **********************************************************************
    #创建二级子进程处理僵尸

    import os

    #创建一级子进程
    pid1 = os.fork()

    if pid1 < 0:
    print("创建一级子进程失败")
    elif pid1 == 0:
    #创建二级子进程
    pid2 = os.fork()
    if pid2 < 0:
    print("创建二级子进程失败")
    elif pid2 == 0:
    print("做另一件任务")
    else:
    #一级子进程退出,使二级子进程成为孤儿
    os._exit(0)
    else:
    #等待一级子进程退出 
    os.wait()
    print("做父进程该做的")
    **********************************************************************
    import multiprocessing as mp
    import os
    import time

    a = 1

    def th1():
    global a
    a = 1000
    print("th1 a",a)
    print(os.getppid(),"----",os.getpid())
    print("吃饭早饭")
    time.sleep(1)
    print("吃饭午饭")
    time.sleep(2)
    print("吃饭晚饭")
    time.sleep(3)

    def th2():
    print(os.getppid(),"----",os.getpid())
    print("睡觉午觉")
    time.sleep(2)
    print("睡觉")
    time.sleep(3)
    print("th2 a:",a)

    def th3():
    print(os.getppid(),"----",os.getpid())
    print("打豆豆")
    time.sleep(2)
    print("打豆豆")
    time.sleep(2)

    #创建三个新的进程,关联上面三个事件
    #生产进程对象分别表示这三个进程
    p1 = mp.Process(target = th1)
    p2 = mp.Process(target = th2)
    p3 = mp.Process(target = th3)

    #通过生成的进程对象启动子进程
    #子进程有父进程的代码段 只不过只执行对应的函数
    p1.start()
    p2.start()
    p3.start()

    print("Parent PID",os.getpid())

    #阻塞等待回收进程
    p1.join()
    p2.join()
    p3.join()

    print("++++++++++++++++++++++++")
    # th1()
    # th2()
    # th3()
    *****************************************************************
    from multiprocessing import *
    from time import sleep

    a = 1

    def worker(sec,msg):
    print("a = ",a)
    for i in range(3):
    sleep(sec)
    print("worker message:",msg)

    # 位置传参
    # p = Process(target = worker,args = (2,"hello")
    # 字典传参
    p = Process(name="worker",target = worker,
    args = (2,),kwargs = {'msg':"hello"})
    p.start()

    print("p.name :",p.name)
    #p所代表的子进程的PID号
    print("p.pid:",p.pid)
    print("p.alive",p.is_alive())

    p.join()
    *******************************************************************
    import multiprocessing as mp
    import os
    import time

    def th1():
    print(os.getppid(),"----",os.getpid())
    print("吃饭早饭")
    time.sleep(1)
    print("吃饭午饭")
    time.sleep(2)
    print("吃饭晚饭")
    time.sleep(3)

    def th2():
    print(os.getppid(),"----",os.getpid())
    print("睡觉午觉")
    time.sleep(2)
    print("睡觉")
    time.sleep(3)

    def th3():
    print(os.getppid(),"----",os.getpid())
    print("打豆豆")
    time.sleep(2)
    print("打豆豆")
    time.sleep(2)

    things = [th1,th2,th3]
    process = []

    for th in things:
    p = mp.Process(target = th)
    p.daemon = True
    process.append(p)
    p.start()

    print("+++++++父进程++++++++")

    # for i in process:
    # i.join()
    ****************************************************************
    import os,sys
    from time import sleep

    pid = os.fork()

    if pid < 0:
    print("Create process failed")
    elif pid == 0:
    print("Child process...")
    sleep(2)
    sys.exit(2)
    else:
    #设置为非阻塞状态,循环处理查看子进程状态
    while True:
    p,status = os.waitpid(-1,os.WNOHANG)
    sleep(0.5)
    print("parent process")
    print(p,status)
    while True:
    pass
    ********************************************************************
    这是聊天室程序
    server.py

    '''
    name : Levi
    chatroom server
    '''
    from socket import *
    import sys,os

    #实现登录
    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[name] = addr
    return

    def do_chat(s,user,cmd):
    #cmd = ['C','zhang','I','love','China']
    msg = " %-4s: %s"%(cmd[1],' '.join(cmd[2:]))

    #发送给所有人,除了自己
    for i in user:
    if i != cmd[1]:
    s.sendto(msg.encode(),user[i])
    return

    def do_quit(s,user,name):
    del user[name]
    msg = " " + name + "离开了聊天室"
    for i in user:
    s.sendto(msg.encode(),user[i])
    return

    #子进程处理客户端请求
    def do_child(s):
    #字典用来存储用户信息 {name:(ip,port)}
    user = {}
    #循环接受请求
    while True:
    msg,addr = s.recvfrom(1024)
    msg = msg.decode()
    cmd = msg.split(' ')

    #根据不同请求做不同事情
    if cmd[0] == 'L':
    do_login(s,user,cmd[1],addr)
    elif cmd[0] == 'C':
    do_chat(s,user,cmd)
    elif cmd[0] == 'Q':
    do_quit(s,user,cmd[1])
    else:
    s.sendto("请求错误".encode(),addr)

    #发送管理员消息
    def do_parent(s,addr):
    while True:
    msg = input("管理员消息:")
    msg = "C 管理员 "+ msg
    s.sendto(msg.encode(),addr)
    s.close()
    sys.exit(0)

    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)
    s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    s.bind(ADDR)

    #创建子进程
    pid1 = os.fork()

    if pid1 < 0:
    print("创建一级子进程失败")
    elif pid1 == 0:
    #创建二级子进程
    pid2 = os.fork()
    if pid2 < 0:
    print("创建二级子进程失败")
    elif pid2 == 0:
    do_child(s)
    else:
    #一级子进程退出,使二级子进程成为孤儿
    os._exit(0)
    else:
    #等待一级子进程退出 
    os.wait()
    do_parent(s,ADDR)

    if __name__ == "__main__":
    main()

    *******************************************************************

    client.py
    '''
    name:Levi
    chatroom client
    '''
    from socket import *
    import sys,os
    import signal

    #子进程发送消息
    def do_child(s,name,addr):
    while True:
    text = input("发言(输入quit退出):")
    #用户退出
    if text == "quit":
    msg = "Q " + name
    s.sendto(msg.encode(),addr)
    #从子进程中杀掉父进程
    os.kill(os.getppid(),signal.SIGKILL)
    sys.exit("退出聊天室")
    #正常聊天
    else:
    msg = "C %s %s"%(name,text)
    s.sendto(msg.encode(),addr)

    #父进程接收消息
    def do_parent(s):
    while True:
    msg,addr = s.recvfrom(1024)
    print(msg.decode() + " 发言(输入quit退出):",
    end="")

    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)

    while True:
    name = input("请输入姓名:")
    msg = 'L ' + name
    s.sendto(msg.encode(),ADDR)
    data,addr = s.recvfrom(1024)
    if data.decode() == 'OK':
    print("@进入聊天室@")
    break
    else:
    print(data.decode())

    pid = os.fork()
    if pid < 0:
    print("创建子进程失败")
    elif pid == 0:
    do_child(s,name,ADDR)
    else:
    do_parent(s)

    if __name__ == "__main__":
    main()
    ******************************************************************
  • 相关阅读:
    蛇形填数(算法竞赛入门经典)
    35. Search Insert Position(LeetCode)
    70. Climbing Stairs(LeetCode)
    循环结构程序设计(算法竞赛入门经典)课后题
    阶乘之和(算法竞赛入门经典)[求余问题]
    有关int范围的例题(算法竞赛入门经典)
    矩阵行成列,列成行
    543. Diameter of Binary Tree(LeetCode)
    415. Add Strings(LeetCode)
    121. Best Time to Buy and Sell Stock(LeetCode)
  • 原文地址:https://www.cnblogs.com/wcin/p/9114257.html
Copyright © 2011-2022 走看看