zoukankan      html  css  js  c++  java
  • 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("--------")
     
  • 相关阅读:
    jmeter(46) redis
    jmeter(45) tcp/ip协议
    Codeforces Round #538 (Div. 2)D(区间DP,思维)
    Codeforces Global Round 1D(DP,思维)
    Educational Codeforces Round 57D(DP,思维)
    UPC11073(DP,思维)
    Yahoo Progamming Contest 2019D(DP,思维)
    Atcoder Beginner Contest 118D(DP,完全背包,贪心)
    Xuzhou Winter Camp 1C(模拟)
    Educational Codeforces Round 57 (Rated for Div. 2)D(动态规划)
  • 原文地址:https://www.cnblogs.com/vivian0119/p/11406198.html
Copyright © 2011-2022 走看看