day38作业

1、整理GIL解释器锁,解释以下问题
1、什么是GIL

  Global  Interpreter  Lock 全局解释器锁
2、有了GIL会对单进程下的多个线程造成什么样的影响

  使得单进程下的多线程按照串行的方式使用解释器资源。
3、为什么要有GIL

  放置线程竞争解释器资源,导致使用出错,也使得解释器的内部数据被多线程修改出现错误。
4、GIL与自定义互斥锁的区别,多个线程争抢GIL与自定义互斥锁的过程分析

  全局锁不能保证自己开启的线程安全  但是保证解释器中的数据的安全的

  GIL 在线程调用解释器时 自动加锁  在IO阻塞时或线程代码执行完毕时 自动解锁

  自定义互斥锁需要自己手动上锁,手动释放。
5、什么时候用python的多线程,什么时候用多进程,为什么?

  多线程用于密集io操作的程序,而多进程多用于密集计算的程序当中,因为全局解释器锁对于,单一进程下的多进程使用一个cpu核心,多io操作的程序主要消耗时间为io操作,使用多线程内存消耗小,效率不下于多进程。对于密集计算型程序,使用多进程的每个cpu的核心都能被利用,效率大于单核心的处理。

2、进程池与线程池

1、池的用途,为何要用它

  就是一个装进程的容器

2、池子里什么时候装进程什么时候装线程?

  密集io操作的程序使用多线程、密集计算的操作使用多进程

3、基于进程池与线程池实现并发的套接字通信

客户端

import socket

client = socket.socket()
client.connect(("127.0.0.1",3555))
while True:
    msg = input(">>>")
    client.send(msg.encode("utf-8"))
    data = client.recv(1024)
    print(data.decode("utf-8"))

服务端(进程池和线程池)

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
#导入进程池
import socket

def task(client):
    while True:
        try:
            data = client.recv(1024)
            print(data.decode("utf-8"))
            if not data:
                client.close()
                break
            client.send(data.upper())
        except Exception:
            print("客户端断开")
            client.close()
            break

if __name__ == '__main__':
    server = socket.socket()
    server.bind(("127.0.0.1",3555))
    server.listen(5)
    #创建进程池默认个数为cpu的核心数
    # pool = ProcessPoolExecutor()
    #创建线程池默认个数为cpu核心的5倍
    pool = ThreadPoolExecutor()
    while True:
        client,addr = server.accept()
        pool.submit(task,client)

4、基于线程池实现一个可以支持并发通信的套接字,完成以下功能?

执行客户端程序,用户可选的功能有:
1、登录
2、注册
3、上传
4、下载

思路解析:
1、执行登录,输入用户名egon,密码123,对用户名egon和密码进行hash校验,并加盐处理,将密文密码发送到服务端,与服务端事先存好用户名与密文密码进行对比,对比成功后,
在服务端内存中用hash算法生成一个随机字符串比如eadc05b6c5dda1f8772c4f4ca64db110
然后将该字符串发送给用户以及登录成功的提示信息发送给客户端,然后在服务存放好
current_users={
'a3sc05b6c5dda1f8313c4f4ca64db110':{'uid':0,'username':'alex'},
'e31adfc05b6c5dda1f8772c4f4ca64b0':{'uid':1,'username':'lxx'},
'eadc05b6c5dda1f8772c4f4ca64db110':{'uid':2,'username':'egon'},

}

用户在收到服务端发来的'eadc05b6c5dda1f8772c4f4ca64db110'以及登录成功的提示信息后,以后的任何操作都会携带该随机字符串'eadc05b6c5dda1f8772c4f4ca64db110‘,服务端会根据该字符串获取用户信息来进行与该用户匹配的操作

在用户关闭连接后,服务端会从current_users字典中清除用户信息,下次重新登录,会产生新的随机字符串
这样做的好处:
1、用户的敏感信息全都存放到服务端,更加安全
2、每次登录都拿到一个新的随机的字符串,不容易被伪造

2、执行注册功能,提交到服务端,然后存放到文件中,如果用户已经存在则提示用户已经注册过,要求重新输入用户信息

3、执行上次下载功能时会携带用户的随机字符串到服务端,如果服务端发现该字符串not in current_users,则要求用户先登录

 客户端

import socket,struct,json,hashlib,os

client = socket.socket()
client.connect(("127.0.0.1",4566))
current_code = None

def send_data_to_server(data):
    """

    :param client: 连接
    :param data: 符合json格式的数据
    :return:
    """
    json_data = json.dumps(data)
    # 在转化可传输的二进制形式
    bytes_data = json_data.encode("utf-8")
    # 计算传输需要的的长度
    len_bytes = len(bytes_data)
    # 将长度整形打包成为二进制位
    b_len = struct.pack("i", len_bytes)
    # 传输数据
    client.send(b_len)
    client.send(bytes_data)

def get_recv_data():
    """
    接受服务返回的数据
    :param client:
    :return:
    """
    b_len = client.recv(4)
    # 转换为数字
    bytes_len = struct.unpack("i", b_len)[0]
    recv_data = b""
    len_recv = 0
    while len_recv < bytes_len:
        r_data = client.recv(1024)
        recv_data += r_data
        len_recv += len(r_data)
    str_data = recv_data.decode("utf-8")
    data = json.loads(str_data)
    return data

def encryption(pwd):
    res = hashlib.md5(pwd.encode("utf-8"))
    return res.hexdigest()

def regist():
    """
    注册
    :return:
    """
    while True:
        name = input("请输入你的姓名(q 退出)").strip()
        if name == "q":
            return
        pwd = input("请输入你的密码").strip()
        if name and pwd:
            func_id = 1
            pwd = encryption(pwd)
            dic = {"name":name,"pwd":pwd,"func_id":func_id}
            send_data_to_server(dic)
            #等待接收服务端的返回
            msg_dic = get_recv_data()
            print(msg_dic["msg"])
            if msg_dic["flag"]:
                return
        else:
            print("用户和密码不能为空")

def login():
    """
    登录,获得连接特征码
    :return:
    """
    while True:
        name = input("请输入你的姓名(q 退出)").strip()
        if name == "q":
            return
        pwd = input("请输入你的密码").strip()
        if name and pwd:
            func_id = 1
            pwd = encryption(pwd)
            dic = {"name": name, "pwd": pwd, "func_id": func_id}
            send_data_to_server(dic)
            msg_dic =get_recv_data()
            print(msg_dic["msg"])
            if msg_dic["flag"]:
                global current_code
                current_code = msg_dic["current_code"]
                return 
        else:
            print("用户名和密码不能为空")
#上传
def upload():
    while True:
        filename = input("请输入文件路径(q 退出)").strip()
        if filename == 'q':
            return 
        if not filename:
            print("文件名不能为空")
            continue
        if os.path.exists(filename):
            file_name = os.path.split(filename)[1]
            file_size = os.path.getsize(filename)
            file_dic = {"file_name":file_name,"file_size":file_size,"current_code":current_code}
            send_data_to_server(file_dic)
            with open(filename,"rb") as f:
                for line in f:
                    client.send(line)
                    
            msg_dic = get_recv_data()
            print(msg_dic["msg"])
            if msg_dic["flag"]:
                return 
        else:
            print("文件路劲不存在")
            continue


#下载
def download():
    while True:
        filename = input("请输入下文件的名字(q 退出)").strip()
        if filename == "q":
            return 
        if not filename:
            print("文件不能为空")
            continue
        dic = {"filename":filename}
        send_data_to_server(dic)
        file_dic = get_recv_data()
        print(file_dic["msg"])
        if file_dic["flag"]:
            filename = file_dic["filename"]
            filesize = file_dic["file_size"]
            file_path = os.path.join(r"F:Python_exeday38userdb",filename)
            b_len = 0
            with open(file_path,"ab") as f:
                while b_len<filesize:
                    data = client.recv(1024)
                    f.write(data)
                    b_len += len(data)
            return 
        
        

func = {"1":regist,"2":login,"3":upload,"4":download}
while True:
    print("""
    1、注册
    2、登录
    3、上传
    4、下载
    q 退出
    """)
    index = input("请输入你想要的操作").strip()
    if index == "q":
        break
    if index in func:
        func[index]()
    else:
        print("错误操作")

 服务端

from concurrent.futures import ThreadPoolExecutor
import socket,struct,json
import hashlib
import time
import os

server  = socket.socket()
server.bind(("127.0.0.1",4566))
server.listen(5)
current_user = {}

def get_recv_data(client):
    """
    接受服务返回的数据
    :param client:
    :return:
    """
    b_len = client.recv(4)
    # 转换为数字
    bytes_len = struct.unpack("i", b_len)[0]
    recv_data = b""
    len_recv = 0
    while len_recv < bytes_len:
        r_data = client.recv(1024)
        recv_data += r_data
        len_recv += len(r_data)
    str_data = recv_data.decode("utf-8")
    data = json.loads(str_data)
    return data

#发送个客户端
def send_data_to_client(client,data):
    """

    :param client: 连接
    :param data: 符合json格式的数据
    :return:
    """
    json_data = json.dumps(data)
    # 在转化可传输的二进制形式
    bytes_data = json_data.encode("utf-8")
    # 计算传输需要的的长度
    len_bytes = len(bytes_data)
    # 将长度整形打包成为二进制位
    b_len = struct.pack("i", len_bytes)
    # 传输数据
    client.send(b_len)
    client.send(bytes_data)

#用户是否存在
def get_user(name):
    with open(r"F:Python_exeday38user_db.json","r",encoding="utf-8") as f:
        users = json.load(f)
    for user in users:
        if user["name"] == name:
            return user

#添加用户到文件中去
def save_user_to_file(name,pwd):
    dic = {"name":name,"pwd":pwd}
    with open(r"F:Python_exeday38user_db.json","r",encoding="utf-8") as f:
        users = json.load(f)
    users.append(dic)
    with open(r"F:Python_exeday38user_db.json", "w", encoding="utf-8") as f:
        json.dump(users,f)


def regist(client,data):
    name = data["name"]
    pwd = data["pwd"]
    #校验用户是否存在
    user = get_user(name)
    if user:
        msg = "用户已存在"
        flag = False
    else:
        save_user_to_file(name,pwd)
        msg = "创建用户成功"
        flag = True
    msg_dic = {"msg":msg,"flag":flag}
    send_data_to_client(client,msg_dic)#发送给客户端

def login(client,data):
    name = data["name"]
    pwd = data["pwd"]
    # 校验用户是否存在
    user = get_user(name)
    if user:
        if pwd == user["pwd"]:
            msg = "登录成功"
            flag = True
            #生成一个current_code加入current_user,并返回一个current_code给客户端
            code = "%s%s%s"%(name,pwd,time.time())
            current_code = hashlib.md5(code.encode("utf-8")).hexdigest()
            current_user[current_code] = {"username":name}
            msg_dic = {"msg":msg,"flag":flag,"current_code":current_code}
        else:
            msg = "密码错误"
            flag = False
            msg_dic = {"msg": msg, "flag": flag}
    else:
        msg = "用户不存在,请先注册"
        flag = False
        msg_dic = {"msg": msg, "flag": flag}

    send_data_to_client(client,msg_dic)

def upload(client,data):
    if data["current_code"] in current_user:
        file_name = data["file_name"]
        file_size = data["file_size"]
        by_len = 0
        with open(r'F:Python_exeday38server_db\%s'%file_name,"ab") as f:
            while by_len<file_size:
                data = client.recv(1024)
                f.write(data)
                by_len += len(data)
        msg = "上传成功"
        flag = True
    else:
        msg = "用户认证失败"
        flag = False
    msg_dic = {"msg":msg,"flag":flag}
    send_data_to_client(client,msg_dic)


def download(client,data):
    filename = data["filename"]
    file_path = os.path.join("F:Python_exeday38server_db",filename)
    if not os.path.exists(file_path):
        msg = "文件不存在"
        flag = False
        file_dic = {"msg":msg,"flag":flag}
        send_data_to_client(client, file_dic)
    else:
        msg = "文件存在"
        flag = True
        file_size = os.path.getsize(file_path)
        file_dic = {"msg":msg,"flag":flag,"filename":filename,"file_size":file_size}
        send_data_to_client(client,file_dic)
        with open(file_path,"rb") as f:
            for line in f:
                client.send(line)



#总成函数
def task(client):
    while True:
        try:
            data = get_recv_data(client)
            print(data)
            if not data:
                client.close()
                return
            #功能列表
            funs = {"1":regist,"2":login,"3":upload}
            print(1)
            func_id = data["func_id"]
            print(2)
            funs[str(func_id)](client,data)
            print(3)
        except Exception:
            print("客户端断开连接")
            client.close()
            break





pool = ThreadPoolExecutor()
while True:
    client,addr = server.accept()
    pool.submit(task,client)
原文地址:https://www.cnblogs.com/msj513/p/9949261.html