day31:socketserver&hashlib&hmac&TCP登录
目录
1.socketserver:实现TCP协议下Server端的并发
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()