day31:socketserver&hashlib&hmac&TCP登录

目录

1.socketserver:实现TCP协议下Server端的并发

2.hashlib模块

3.hashlib应用:文件校验

4.hmac应用:服务器的合法性校验

5.TCP登录程序

1.socketserver:实现TCP协议下Server端的并发

1.socketserver的基本语法

服务端

# ### 服务端
import socketserver

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        print("handle方法被执行了")
        
# ThreadingTCPServer(ip端口号,自定义的类)
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , MyServer )
# 建立连接,循环调用
server.serve_forever()

客户端

# ### 客户端
import socket
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )

# 处理收发数据的逻辑

sk.close()

2.socketserver实现server端的并发

服务端

# ### 服务端
import socketserver

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        conn = self.request # self.request就是我们之前熟悉的conn对象
        while True:
            # 接受数据
            msg = conn.recv(1024)
            msg2 = msg.decode("utf-8")
            
            print(msg2)
            conn.send(msg2.upper().encode())
                
# ThreadingTCPServer(ip端口号,自定义的类)
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , MyServer )
# 建立连接,循环调用
server.serve_forever()

客户端

# ### 客户端
import socket
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )
# 处理收发数据的逻辑
while True:
    sk.send(b"you can you up no can no bb")

    msg = sk.recv(1024)
    print(msg.decode("utf-8"))
sk.close()

3.关于sockerserver,你需要注意:.

1.在server端定义MyServer类,继承BaseRequestHandler类

2.收发数据的逻辑都写在MyServer类下的handler方法中,注意!函数名只能为handle,不可以乱起函数名

3.定义完类,要做两件事

  server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , MyServer )

  server.serve_forever()

2.hashlib模块

1.基本用法

# 基本用法
# 1.创建一个md5算法的对象
hm = hashlib.md5()
# 2.把要加密的字符串通过update更新到hm这个对象中运算
hm.update("123456".encode("utf-8")) # 里面的数据必须是二进制字节流
# 3.获取32位16进制字符串
res = hm.hexdigest() 

2.味道不够?加盐!!

什么是加盐? 加盐(加key => Xboy_) 加一个关键字配合原字符进行加密,是密码更复杂,不容易被破解

# 加盐(加key => Xboy_) 加一个关键字配合原字符进行加密,是密码更复杂,不容易被破解
hm = hashlib.md5("Xboy_wangwen".encode())
hm.update("123456".encode())
res = hm.hexdigest()
print(res , len(res))

3.进阶版:动态加盐

通过引入随机数模块,每次都生成一个不同的数字和密码进行加密

# 动态加盐
num = str(random.randrange(100000,1000000))
hm = hashlib.md5(num.encode("utf-8"))
hm.update("123456".encode())
res = hm.hexdigest()

4.除了常见的md5加密,还有sha加密

sha和md5的不同之处:

sha 算出来的十六进制的串是40位,加密稍慢,安全性稍高

md5 算出来的十六进制的串是32位,加密很快,安全性稍差

# sha1版本
hs = hashlib.sha1()
hs.update("我最是牛逼的&#*($&*(#&%*(&%*&%(#%&".encode())
res = hs.hexdigest()
print(res, len(res)) # 31673dd65f81fddaae07b4240cbb04af047b7496

# sha512版本
hs = hashlib.sha512()
hs.update("123456".encode())
res = hs.hexdigest()
print(res , len(res))

5.还有更牛逼的hmac加密

hmac加密的优势:hmac 加密算法更加复杂,不容易破解

1.基本语法

import hmac
# hmac.new(盐,密码)
key = b"a"
msg = b"123456"
hn = hmac.new(key,msg)
res = hn.hexdigest()
print(res, len(res)) # 32位长度 十六进制的字符串

2.动态加盐

在加盐前,我们需要了解一个知识:通过os.urandom 可以返回随机的二进制字节流

key = os.urandom(32)
msg = b"123"
hn = hmac.new(key,msg)
res = hn.hexdigest()
print(res, len(res))

3.hashlib应用:文件校验

1.针对于小文件进行内容校验

# (1) 针对于小文件进行内容校验
def check_md5(filename):
    hs = hashlib.md5() # 创建md5加密对象
    with open(filename,mode="rb") as fp: # 打开文件            
        hs.update(fp.read()) # 将读出的内容(字符串)通过update更新到hs对象中进行加密运算
    return hs.hexdigest() # 返回加密后的16进制字符串
    
res1 = check_md5("ceshi1.txt")
res2 = check_md5("ceshi2.txt")
print(res1,res2)

2.针对于大文件进行内容校验

针对于大文件进行内容校验,我们可以通过update 把字符串分段进行加密

# 常规方法
strvar = "今天是星期五,好开心了,下周一又要考试了."
hm = hashlib.md5()
hm.update(strvar.encode())
res = hm.hexdigest()
print(res)

# 分段更新加密
hm = hashlib.md5()
hm.update("今天是星期五,好开心了,".encode())
hm.update("下周一又要考试了.".encode())
res = hm.hexdigest()
print(res)

通过运行我们可以发现两个res的值是相同的,说明了大文件分段加密是可行的

3.用文件操作对大文件进行分段加密 

方法一

# 方法一
def check_md5(filename):
    hs = hashlib.md5() # 先弄个md5的加密对象
    with open(filename,mode="rb") as fp: # 打开文件
        while True:
            content = fp.read(10) # 一次最多读取10个字节
            if content: # 读取到了内容:代表文件里还有东西
                # 分批进行字符串密码更新
                hs.update(content)
            else: # 读取不到内容:代表文件已经全读取完了,可以结束了
                break

        return hs.hexdigest()

    
res1 = check_md5("ceshi1.txt")
res2 = check_md5("ceshi2.txt")
print(res1,res2)

方法二

def check_md5(filename):
    hs = hashlib.md5()
    # 计算文件大小=>返回字节数
    filesize = os.path.getsize(filename) # 先获取到文件的大小
    with open(filename,mode="rb") as fp: # 打开文件
        while filesize: # 当文件大小不为0时            
            content = fp.read(10) # 一次最多读取10个字节
            hs.update(content) # 读一点更新一点
            # 按照实际的字节个数读取
            filesize -= len(content)
            
        return hs.hexdigest()

res1 = check_md5("ceshi1.txt")
res2 = check_md5("ceshi2.txt")
print(res1,res2)

4.hmac应用:服务器的合法性校验

服务端:

def auth(conn,secret_key):
    # 随机产生32位的二进制字节流
    msg = os.urandom(32)
    conn.send(msg)

    hn = hmac.new(secret_key.encode(),msg)
    res_server = hn.hexdigest()
    print(res_server) # 461ea12ca8ef475caeedd0c742f4295e
    
    # 服务端接受客户端发送过来的数据进行验证;
    res_client = conn.recv(1024).decode("utf-8")
        
    if res_client == res_server:
        print("你是合法的服务端用户")
        return True
    else:
        print("不是合法的服务端用户")
        return False


sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind( ("127.0.0.1",9000) )
sk.listen()

# 三次握手
conn,addr = sk.accept()

# 处理收发数据的逻辑
secret_key = "芝麻开门"
res = auth(conn,secret_key)

# 在验证成功之后,给客户端发送状态码
if res:
    conn.send("状态码是200:付款成功~".encode())
# 四次挥手
conn.close()
# 退还端口
sk.close()

客户端:

def auth(sk,secret_key):
    # 处理收发数据的逻辑
    msg = sk.recv(32)
    hn = hmac.new(secret_key.encode(),msg)
    res = hn.hexdigest()
    
    # 把客户端加密的字符串发送给服务端进行验证
    sk.send(res.encode("utf-8"))


sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )

# 处理收发数据的逻辑
secret_key = "芝麻开门123"
auth(sk,secret_key)

# 在验证成功之后,接受服务端给我的验证码
res = sk.recv(1025).decode("utf-8")
print(res)

sk.close()

5.TCP登录程序

服务端:

def get_md5_code(usr,pwd):
    hs = hashlib.md5(usr.encode())
    hs.update(pwd.encode())
    return hs.hexdigest()

# res = get_md5_code("tianqi","777")
# print(res)

sk = socket.socket()
sk.bind( ("127.0.0.1", 9001) )
sk.listen()
conn,addr = sk.accept()


# 处理收发数据的逻辑
msg = conn.recv(1024).decode()
# 把反解之后的字符串恢复原来的数据格式变成字典通过json
dic = json.loads(msg)
print(dic)

sign = False
with open("userinfo.txt",mode="r",encoding="utf-8") as fp:
    for line in fp:
        usr,pwd = line.strip().split(":")
        # print(usr,pwd)
        if usr == dic["username"] and pwd == get_md5_code(dic["username"],dic["password"]):
            # 制定状态码 0=>失败 1=>成功
            res = {"code":1}
            res_msg = json.dumps(res).encode()
            conn.send(res_msg)
            sign = True
            break

if sign == False:
    # 发送错误的状态码
    res = {"code":0}
    res_msg = json.dumps(res).encode()
    conn.send(res_msg)
    

客户端:

sk = socket.socket()
sk.connect( ("127.0.0.1", 9001) )

# 处理收发数据的逻辑
usr = input("请输入您的用户名:")
pwd = input("请输入您的密码:")
dic = {"username":usr,"password":pwd,"operate":"login"}
# 先通过json变成字符串
res = json.dumps(dic)
# json字符串 -> 字节流
bytes_msg = res.encode()
# 把字节流发送给服务端
sk.send(bytes_msg)


# 接受服务端发送过来的数据
res_msg = sk.recv(1024).decode()
dic_code = json.loads(res_msg)

if dic_code["code"]:
    print("恭喜你~ 登录成功")
else:
    print("i am so sorry ~ 登录失败")

sk.close()
原文地址:https://www.cnblogs.com/libolun/p/13504198.html