• python学习之路day09(黏包、md5和进程守护)


    1.黏包

    (一)发生黏包

    a.# ###服务端
    import socket
    sk=socket.socket()
    sk.bind(("127.0.0.1",9000))
    sk.listen()

    #三次握手
    conn,addr=sk.accept()
    #收发数据逻辑
    conn.send("hello,".encode())
    conn.send("world".encode())
    #四次挥手
    conn.close()
    #退还端口
    sk.close()
    b.# ###客户端
    import socket,time
    sk=socket.socket()
    sk.connect(("127.0.0.1",9000))

    time.sleep(0.1)
    print(sk.recv(10))
    print(sk.recv(10))

    sk.close()

    """
    总结:导致黏包现象的两种情况
    hello,world
    (1)在发送端,发送数据太快,频繁发送
    (2)在接收端,接收数据太慢,延迟截取
    """

    (二)解决方法一

    a.### #服务端
    import socket
    sk=socket.socket()
    sk.bind(("127.0.0.1",9000))
    sk.listen()
    conn,addr=sk.accept()
    #收发数据的逻辑
    #告诉接收端,我要发送的数据长度是多少
    conn.send("6".encode())
    #发送的实际数据
    conn.send("hello,".encode())
    conn.send("world".encode())
    conn.close()
    sk.close()
    b.### #客户端
    import socket,time
    sk=socket.socket()
    sk.connect(("127.0.0.1",9000))

    time.sleep(0.1)
    #收发数据逻辑
    n=int(sk.recv(1).decode())
    print(n,type(n))
    print(sk.recv(n))
    print(sk.recv(10))

    sk.close()

    (三)解决方法二

    a.### #服务端
    import socket
    sk=socket.socket()
    sk.bind(("127.0.0.1",9000))
    sk.listen()
    conn,addr=sk.accept()
    #收发数据的逻辑
    #告诉接收端,我要发送的数据长度是多少
    conn.send("00000120".encode())
    #发送的实际数据
    msg="hello," * 20
    conn.send(msg.encode())
    conn.send("world".encode())
    conn.close()
    sk.close()
    b.### #客户端
    import socket,time
    sk=socket.socket()
    sk.connect(("127.0.0.1",9000))

    time.sleep(0.1)
    #收发数据逻辑
    n=int(sk.recv(8).decode())
    print(n,type(n))
    print(sk.recv(n))
    print(sk.recv(10))

    sk.close()

    (四)解决方法三

    a.# ###服务端
    import socket,struct
    sk=socket.socket()
    sk.bind(("127.0.0.1",9000))
    sk.listen()
    conn,addr=sk.accept()
    #收发数据逻辑
    inp=input("message>>>:")
    msg=inp.encode()
    #把长度的数字转换成二进制字节流,然后发送给对面,按照这么大的长度进行截取
    res=struct.pack("i",len(msg))
    conn.send(res)
    conn.send("world".encode())
    #四次挥手
    conn.close()
    #退还端口
    sk.close()

    """
    字节流是一个一个字节组成的,凑在一起,就是字节流
    总长度就是一共的字节数,用len算字节流长度,告诉接收端,要截取多少个字节
    """
    # ###客户端
    import socket,time,struct
    sk=socket.socket()
    sk.connect(("127.0.0.1",9000))
    time.sleep(0.1)
    #先接收要截取的长度是多少
    n=sk.recv(4)
    n=struct.unpack("i",n)[0]
    print(n)
    #再去接收真实的数据,防止黏包
    print(sk.recv(n))
    print(sk.recv(10))

    sk.close()
    b.# ###客户端
    import socket,time,struct
    sk=socket.socket()
    sk.connect(("127.0.0.1",9000))
    time.sleep(0.1)
    #先接收要截取的长度是多少
    n=sk.recv(4)
    n=struct.unpack("i",n)[0]
    print(n)
    #再去接收真实的数据,防止黏包
    print(sk.recv(n))
    print(sk.recv(10))

    sk.close()

    2.struct的基本用法
    #struct 基本用法
    import struct
    #pack
    """
    #struct.pack 把任意长度的数字转化成具有固定长度的4个字节的值,组成字节流
    pack("i/f/s",2100000000) 代表我要转换的这个数据类型是整型,这个整型一般放的是字节长度;
    i ==>int
    """
    #unpack
    """
    #struct.unpack 把4个字节的值恢复成原有的数据,返回的是元组
    uppack("i") 代表我要转换的这个数据类型是整型,这个整型一般放的是字节长度;
    """
    res=struct.pack("i",10000) #b"x10'x00x00"
    res=struct.pack("i",2100000000) #b'x00xe1xf5x05'
    #小于22亿的长度范围
    # res=struct.pack("i",13000000000) #erro
    print(res)
    print(len(res)) #4

    # "i" 把二进制字节流转换成整型,返回的是元组,通过下标0直接拿到数据
    res=struct.unpack("i",res)[0]
    print(res) #2100000000

    3.### #socketserver 实现tcp链接的并发操作
    a.###服务端
    """
    文件<==>模块
    文件夹<==>包
    """
    import socketserver
    class Myserver(socketserver.BaseRequestHandler):
    #默认调用handle
    def handle(self):
    #self.request 相当于socketserver 底层已经给你封装好了,直接拿来用就可以;
    conn=self.request
    print(self.client_address)
    while True:
    msg=conn.recv(1024).decode("utf-8")
    print(msg)
    conn.send(msg.upper().encode("utf-8"))

    #创建一个对象 ThreadingTCPServer 创建 ThreadingTCPServer((ip,port),自定义类)
    server=socketserver.ThreadingTCPServer(("127.0.0.1",9000),Myserver)
    #循环调用
    server.serve_forever()
    b.### #客户端
    import socket
    sk=socket.socket()
    sk.connect(("127.0.0.1",9000))
    while True:
    sk.send(b"hello")
    msg=sk.recv(1024)
    print(msg)
    # sk.recv()
    sk.close()


    5.# ###hashilib 模块
    import hashlib
    import random
    #基本用法
    #(1)创建一个md5算法的对象
    hs=hashlib.md5()
    #(2) 把想要加密的字符串通过update进行更新到hs对象中进行处理
    hs.update("abc@123".encode())
    #(3)返回32位16进制的字符串
    res=hs.hexdigest()
    print(res,len(res)) #b24331b1a138cde62aa1f679164fc62f 32

    #加盐 (key 只有自己知道的关键字,目的就是增加密码的复杂度)
    hs=hashlib.md5("Xboy_".encode("utf-8"))
    hs.update("abc@123".encode())
    res=hs.hexdigest()
    print(res) #6036d50f3aac0502f96391543ccf06a6

    #动态加盐
    res=str(random.randrange(10000,100000))
    hs=hashlib.md5(res.encode())
    hs.update("abc@123".encode())
    res=hs.hexdigest()
    print(res) #c4d025cb4c90cc33ed4d91bfd9428f62 不断变化

    """
    #md5 加密效率快,安全性不是太高,位数32位的16进制的字符串
    #sha 加密效率慢,安全性稍高,更加精度,位数是40位的16进制字符串
    #sha512 加密效率慢,安全性稍高,更加精确,位数是128位的16进制字符串
    """
    #sha 算法系列
    # hs=hashlib.sha1()
    hs=hashlib.sha512()
    hs.update("abc@123".encode())
    hm=hs.hexdigest()
    print(hm) #ddac418a1be76098d01107464026f65d2a3192bf

    # ###hmac
    """加密的字符串强度更高,不容易破解"""
    import hmac
    key=b"xboyww"
    msg=b"abc@123"
    hm=hmac.new(key,msg)
    res=hm.hexdigest()
    print(res,len(res)) #ead7141d73206994b399111ac7baa4dc
    #随机返回长度为32位的二进制字节流
    import os
    key=os.urandom(32)
    #b"Rxb5dPxbexe5_x1dx05x92xa6xe2Rxbcx13xddxd5Uxb1'xf4xf3x13nx1dx82T3xfcx80a*"
    print(key,len(key))
    hm=hmac.new(key,msg)
    res=hm.hexdigest()
    print(res) #32位变化的 随urandom变化而变化
    6.# ###文件校验
    import hashlib
    """
    read 在mode="r" 读取的单位是字符;
    read 在mode="rb" 读取的单位是字节;
    """
    """
    with open("ceshi111",mode="r",encoding="utf-8") as fp:
    res=fp.read(3)
    print(res) #宇宙无

    with open("ceshi111",mode="rb") as fp:
    res=fp.read(3)
    print(res) #b'xe5xaex87'
    print(res.decode()) #宇
    """

    #(1)针对小文件的内容校验
    def check_md5(file):
    with open("ceshi111",mode="rb") as fp:
    hs=hashlib.md5()
    hs.update(fp.read())
    return hs.hexdigest()
    #如果两个加密的32位字符串相同,就可以说明两个文件的内容是一样的
    res1=check_md5("ceshi111")
    res2=check_md5("ceshi222")
    print(res1)
    print(res2)

    # (2) 针对大文件的内容校验
    hs=hashlib.md5()
    hs.update("昨天晚上 拉肚子了。。。".encode())
    hm=hs.hexdigest()
    print(hm) #a4ee21e6c85406587ec2bf552019bce1
    #可以利用update,分次更新内容
    #利用update 这个特性,可以把较大的内容分次进行加密
    hs=hashlib.md5()
    hs.update("昨天晚上 ".encode())
    hs.update("拉肚子了。。。".encode())
    hm=hs.hexdigest()
    print(hm) #a4ee21e6c85406587ec2bf552019bce1

    #方法一 不停的读字节,直到为空的时候,终止循环
    def check_md5(file):
    #创建对象
    hs=hashlib.md5()
    with open(file,mode="rb") as fp:
    while True:
    #按照每次读取一个字节
    contenty=fp.read(1)
    #如果读取的是空字节,直接break
    if contenty:
    hs.update(contenty)
    else:
    break
    return hs.hexdigest()
    print("-----------")
    #6a37ee1a2aab185df995beca6351231d 加空格的md5
    print(check_md5("ceshi111")) #331f05042466475cba193bfa49caa463
    print(check_md5("ceshi222")) #331f05042466475cba193bfa49caa463


    # 方法二 不停减去响应的字节数,直到减到0,循环终止
    import os
    #计算文件大小,os.path.getsize(file)
    def check_md5(file):
    file_size=os.path.getsize(file)
    # print(file_size)
    hs=hashlib.md5()
    with open(file,mode="rb") as fp:
    while file_size:
    content=fp.read(1)
    hs.update(content)
    #按照实际读取的字节数进行相减
    file_size-=len(content)
    return hs.hexdigest()
    print("-----")
    print(check_md5("ceshi111"))
    print(check_md5("ceshi222"))
    7.# ###进程
    #获取进程号  =>相当于身份证,唯一
    import os
    #获取当前进程ID
    # res=os.getpid()
    # print(res) #一直变化
    # #获取父进程
    # res=os.getppid()
    # print(res) #407 不变

    #(1)进程的基本用法
    from multiprocessing import Process
    import time
    """
    def func():
    print("222>>>当前子进程ID>>>:%s,它的父进程ID>>>:%s"%(os.getpid(),os.getppid()))

    if __name__ == '__main__':
    print("111>>>1.子进程:%s,2.父进程:%s"%(os.getpid(),os.getppid()))
    #创建子进程
    '''target=函数,单独用一个进程去执行谁,去完成哪个任务'''
    p=Process(target=func)
    #调用子进程
    p.start()
    """
    """
    222>>>1.子进程:1226,2.父进程:407
    111>>>当前子进程ID>>>:1227,它的父进程ID>>>:1226
    """

    #(2) 带有参数的函数
    '''
    异步程序:不等每一行代码执行结束,就往下执行其他代码是异步程序

    创建进程的时候,需要创建 -> 就绪,cpu才能过来执行绪态的程序
    创建进程时,需要分配空间,分配空间时,会出现阻塞现象
    '''
    '''
    def func():
    for i in range(5):
    print("222>>>当前子进程ID>>>:%s,它的父进程ID>>>:%s" % (os.getpid(), os.getppid()))

    if __name__ == '__main__':
    print("111>>>1.子进程:%s,2.父进程:%s" % (os.getpid(), os.getppid()))
    #创建进程,返回进程对象
    p=Process(target=func)
    p.start()
    n=5
    for i in range(1,n+1):
    print("*" *i )
    '''
    '''
    def func(n):
    for i in range(1,n+1):
    time.sleep(0.1)
    print("222>>>当前子进程ID>>>:%s,它的父进程ID>>>:%s" % (os.getpid(), os.getppid()))

    if __name__ == '__main__':
    print("111>>>1.子进程:%s,2.父进程:%s" % (os.getpid(), os.getppid()))
    n=5
    """args=(参数1,参数2.....),args类型是元组"""
    p=Process(target=func,args=(n,))
    p.start()
    for i in range(1, n + 1):
    time.sleep(0.1)
    print("*" * i)
    '''
    '''
    111>>>1.子进程:1404,2.父进程:407
    222>>>当前子进程ID>>>:1405,它的父进程ID>>>:1404
    *
    222>>>当前子进程ID>>>:1405,它的父进程ID>>>:1404
    **
    222>>>当前子进程ID>>>:1405,它的父进程ID>>>:1404
    ***
    222>>>当前子进程ID>>>:1405,它的父进程ID>>>:1404
    ****
    222>>>当前子进程ID>>>:1405,它的父进程ID>>>:1404
    *****

    '''

    #(3) 进程之间的数据,彼此是隔离的
    '''
    count=99
    def func():
    global count
    count=100
    print(count)
    print("当前子进程ID号:%s"%(os.getpid()))

    if __name__ == '__main__':
    #创建主进程
    p=Process(target=func)
    p.start()
    #为了先让子进程跑完,在执行过程中的count,看看是否通过子进程进行了修改
    time.sleep(1)
    print("我是主进程",count)
    '''

    #(4) 多进程之间的并发
    """
    在程序并发时,因为cpu的调度策略问题,不一定谁先执行,谁后执行
    但是如果遇到阻塞一定会进行切换,任务的执行是互相抢占cpu资源的过程
    以目前程序来看,主进程执行的稍快,子进程稍慢
    主进程和子进程齐头并进往前跑,谁在前不确定,依赖cpu的调度
    """
    '''
    def func(args):
    print("222>>>当前子进程ID>>>:%s,它的父进程ID>>>:%s"%(os.getpid(),os.getppid()))
    print("end",args)
    if __name__ == '__main__':
    for i in range(10):
    Process(target=func,args=(i,)).start()
    print("主进程执行结束")
    '''

    #(5)主进程和父进程之间的关系
    """
    主进程执行完所有代码,开始等待,等待所有子进程全部结束之后,再终止程序

    若不等待,主进程终止,子进程变成僵尸程序
    在后台不停的运行,占用内存和cpu
    因为进程太多,不容易找到,不容易管理
    所以主进程跑完后,再彻底结束程序
    """
    def func(args):
    print("222>>>当前子进程ID>>>:%s,它的父进程ID>>>:%s"%(os.getpid(),os.getppid()))
    time.sleep(0.1)
    print("end",args)
    if __name__ == '__main__':
    for i in range(10):
    Process(target=func,args=(i,)).start()
    print("主进程执行结束")
    # ###jion 功能:等待子进程执行完毕之后,主进程在向下执行
    from multiprocessing import Process
    import time,os
    """
    8.(1) jion 基本用法
    def func():
    print("发送第一份邮件")

    if __name__ == '__main__':
    p=Process(target=func)
    p.start()
    # time.sleep(1)
    '''针对p进程对象来说,必须等p这个进程执行完毕,主进程的代码向下执行'''
    p.join()
    print("发送第二份邮件")
    """
    #(2) 多个子进程通过join加阻塞,可以实现同步控制
    """
    def func(index):
    print("第%s封邮件已经发送。。。"%index)
    # time.sleep(1)
    if __name__ == '__main__':
    lst=[]
    for i in range(10):
    #创建进程 1个主进程 + 10个子进程=11个进程 创建异步程序
    p=Process(target=func,args=(i,))
    #调用进程
    p.start()
    lst.append(p)
    #如果把join加到循环里,当前这个进程对象,join必须执行结束,下一个进程对象才能创建,变成同步程序,而进程的提示是为了提升执行的速度
    # p.join()
    #列表中的每个进程对象,都加上一个join,可以让所有的进程对象都执行完毕,就释放阻塞,往下执行,保证子进程和主进程之间的同步性
    for i in lst:
    i.join()
    # print(lst)
    # p.join()
    print("发送最后一封邮件")
    """

    ### #使用第二种方法创建进程
    """用自定义类的方式创建进程"""
    #(1) 基本使用
    #必须继承父类Process类
    class MyProcess(Process):
    #类似于handle,必须写成run方法
    def run(self):
    print("子进程:%s,父进程:%s" % (os.getpid(),os.getppid()))
    if __name__ == '__main__':
    p=MyProcess()
    p.start()
    print("主进程:{}".format(os.getpid()))
    # (2) 带参数的子进程函数
    class MyProcess(Process):
    def __init__(self,args):
    #必须调用父类的构造方法
    super().__init__()
    #把参数通过arg来进行保存
    self.args=args
    #类似于handle,必须写成run方法
    def run(self):
    print("子进程:%s,父进程:%s" % (os.getpid(),os.getppid()))
    if __name__ == '__main__':
    lst=[]
    #进程的并发是异步程序
    for i in range(10):
    p=MyProcess("参数:%s"%i)
    p.start()
    lst.append(p)
    #等待所有子进程结束再执行主进程代码是同步程序
    for i in lst:
    i.join()
    print("最后打印子进程ID:",os.getpid())
    9.###守护进程  daemon 
    from multiprocessing import Process
    import time
    """
    守护进程语法:
    进程对象.daemon=True
    设置该对象为守护进程
    守护进程需要在start()方法之前设置

    守护进程为主进程守护,主进程代码执行完毕了,该守护进程自动终止
    但其他子进程全部执行完毕之后,主进程彻底终止
    """
    #(1) 基本语法
    """
    def func():
    print("子进程start")
    time.sleep(0.2)
    print("子进程end")
    if __name__ == '__main__':
    p=Process(target=func)
    #在start开始之前设置该进程时守护进程
    p.daemon=True
    p.start()

    time.sleep(2)
    print("主进程执行完毕")
    """
    #(2) 多个子进程的情况
    '''
    2个子进程+1个主进程
    当主进程里面的代码全部执行完毕之后,守护进程自动终止;
    因为func2这个任务进程执行完毕,所有主进程不能立刻终止程序

    代码执行完毕
    和程序执行完毕两回事

    代码执行完毕 意味着守护进程立刻终止
    只有非守护进程(func2)也都执行完毕之后,主进程才会真正结束

    func1 是守护进程
    func2 是非守护进程就是一个普通进程
    默认主进程会等待所有进程执行完毕之后,才会最终终止程序;
    子进程和主进程彼此独立,数据也不共享,为了防止僵尸程序,才是等待的意义
    '''
    """
    def func1():
    count=1
    while True:
    print("*" * count)
    time.sleep(0.5)
    count+=1

    def func2():
    print("func2 start")
    time.sleep(3)
    print("func2 end")
    if __name__ == '__main__':
    p1=Process(target=func1)
    p1.daemon=True
    p2=Process(target=func2)
    p1.start()
    p2.start()

    time.sleep(1)
    print("主进程代码执行完毕")
    """

    #(3) 守护进程的实际用途:报活

    def alive():
    while True:
    print("1号服务器主机。。。。i am ok.....")
    time.sleep(0.5)


    def func():
    print("1号服务器主要负责统计mysql日志")
    time.sleep(3)
    if __name__ == '__main__':
    p1=Process(target=alive)
    p1.daemon=True
    p2=Process(target=func)
    p1.start()
    p2.start()

    #用join 添加一下阻塞,如果join执行结束了,就代表服务器统计日志的功能失效了
    #或者服务器奔溃,机器也会终止程序
    p2.join()
    print("--------")
     
  • 相关阅读:
    学习进度条
    学期总结
    实验四主存空间的分配和回收
    学术诚信与职业道德
    《构建之法》第8,9,10章 读后感
    实验三 进程调度模拟程序
    团队项目:学习四则运算,团队准备 3.0
    团队项目:学习四则运算,团队准备 2.0
    "数学口袋精灵"bug(团队)
    实验二作业调度模拟程序
  • 原文地址:https://www.cnblogs.com/vivian0119/p/11406198.html
Copyright © 2020-2023  润新知