【二十八】Python全栈之路--_socketserver_hashlib_文件校验

1. socketserver

1.1 基础语法

server.py

# ### 服务端
"""socketserver的提出 , 是为了允许在tcp协议下进行并发操作 ... """
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()

client.py

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

# 处理收发数据逻辑

sk.close()

1.2 循环并发执行

多个客户端给服务端发消息,服务端个多个客户端回消息
server.py

# ### 服务端
"""socketserver的提出 , 是为了允许在tcp协议下进行并发操作 ... """
import socketserver

class MyServer(socketserver.BaseRequestHandler):

	# 第五步: 处理收发数据的逻辑写在handle中;
	def handle(self):
		"""
		<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9001), raddr=('127.0.0.1', 33778)>
		('127.0.0.1', 33778)
		handle这个方法被触发了 .... 
		
		print(self.request) 	   # self.request <=> conn
		print(self.client_address) # self.client_address <=> addr
		print("handle这个方法被触发了 .... ")
		"""
		conn = self.request
		while True:
			res = conn.recv(1024)
			res2 = res.decode()
			print(res2)
			conn.send(  res2.upper().encode()  )

# ThreadingTCPServer( ip端口号 , 自定义的类 )
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9001) , MyServer )
# 调用内部相关函数 
server.serve_forever()

client.py

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


# 处理收发数据逻辑
while True:
	sk.send(b'give me five')
	res = sk.recv(1024)
	print(res.decode())

sk.close()

2. hashlib校验

2.1 hashlib的使用

# ### hashlib 
"""
场景: 网站密码加密
hashlib模块的加密原则是单向不可逆的
md5算法 : 可以把字符串变成具有固定长度的32位十六进制字符串
"""

# 撞库
"""
111222  => 00b7691d86d96aebd21dd9e138f90840
222333  => 00b7691d86d96aebd21dd9e138f90842
"""

import hashlib
import random

# ### 基本语法
# (一)md5对象
# 1.创建md5对象
hs = hashlib.md5()
# 2.把要加密的数据更新到对象中  [update => 把字节流更新到对象之后,进行加密]
hs.update("111222".encode("utf-8"))
# 3.获取十六进制的字符串
res = hs.hexdigest()
print(res   ,   len(res))  # 00b7691d86d96aebd21dd9e138f90840 


# 加盐 (加key , 加一个关键字)
hs = hashlib.md5("XBOYww_".encode())
hs.update("111222".encode())
res = hs.hexdigest()
print(res)  # 623e0e8d4ecabd638c36a5e40189ba8f


# 动态加盐
res = str(random.randrange(100000,1000000))
hs = hashlib.md5(res.encode())
hs.update("111222".encode())
res = hs.hexdigest()
print(res)

# (二)sha系列算法
"""无论是加盐 还是 加密密码,都需要数据类型为二进制字节流"""
# hs = hashlib.sha1()  # 结果是具有固定长度40位的十六进制字符串;
hs = hashlib.sha512("XGIRLww_".encode())  # 结果是具有固定长度128位的十六进制字符串
hs.update("sha系列算法".encode())
res = hs.hexdigest()
"""20c2502d0e00bf8fe35ebfbf097049d1f070e7968f30ef3353ff33d311af50da6b3883bfb9ab411f9dc4cdcd2310b39f5815c6dc1c48cd138d07443a6bcdcd11 128"""
print(res , len(res))  

 
# (三)hmac加密算法
import hmac
import os
key = b"xdogaa_"
msg = b"112233"
# new(盐(字节流),密码(字节流) )
hm = hmac.new(key,msg)
res = hm.hexdigest()
"""
eebe14b1c144092121236cb1e3da396a
"""
print(res , len(res))

# 动态加盐
"""
os.urandom(位数) 返回随机的二进制字节流
res = os.urandom(10)
print(res , len(res))
"""

key = os.urandom(64)
msg = b"112233"
hm = hmac.new(key,msg)
res = hm.hexdigest()
print(res , len(res))

2.2 文件校验

# ### 文件校验
"""
mode = "r"  fp.read(3) 3个字符
mode = "rb" fp.read(3) 3个字节
"""
import hashlib
import os
# (1) 针对于小文件进行校验
def check_md5(filename):
	hs = hashlib.md5()
	with open(filename , mode="rb" ) as fp:
		hs.update(fp.read())
		# return fp.read() 仅仅适用于小文件
	return hs.hexdigest()
	
res1 = check_md5("lianxi1.py")
res2 = check_md5("lianxi2.py")
print(res1 == res2)


# (2) 针对于大文件进行校验(如果直接读取,内存爆炸,所以分批读取)
"""update 可以分批次进行加密  等价于一次性加密的结果"""
# update的使用
strvar = "今天是周五,明天自习"
hs = hashlib.md5()
hs.update(strvar.encode())
res1 = hs.hexdigest()
print(res1)

strvar2 = ",周一上午考试,小人射击+计算器"
hs.update(strvar2.encode())
res2 = hs.hexdigest()
print(res2) # 0163aa435c2eea52fac354ba7e6c84da

strvar = "今天是周五,明天自习,周一上午考试,小人射击+计算器"
hs2 = hashlib.md5()
hs2.update(strvar.encode())
print(hs2.hexdigest()) # 0163aa435c2eea52fac354ba7e6c84da

# 方法一
def check_md5(filename):
	hs = hashlib.md5()
	with open(filename,mode="rb") as fp:
		while True:
			# 最多读取5个字节
			content = fp.read(5)
			# 判断读取的字节如果是空,终止循环
			if content:			
				hs.update(content)
			else:
				break
		return hs.hexdigest()

res1 = check_md5("lianxi1.py")
res2 = check_md5("lianxi2.py")
print(res1 , res2)

# 方法二
def check_md5(filename):
	hs = hashlib.md5()
	filesize = os.path.getsize(filename)
	print(filesize)
	with open(filename,mode="rb") as fp:
		# filesize 如果为空,循环终止;
		while filesize:
		    # 最多一次读100个字节,可能读20个、66个等
			content = fp.read(100)
			hs.update(content)
			# 减去实际读取的字节长度
			filesize -= len(content)
		
		return hs.hexdigest()		
		
res1 = check_md5("lianxi1.py")
res2 = check_md5("lianxi2.py")
print(res1 , res2)

3. 服务端的合法性校验

server.py

# ### 服务端
""" 机器和机器之间的数据直接对接 """
import socketserver
import hmac
import os

class MyServer(socketserver.BaseRequestHandler):

	secret_key = "小兔儿乖乖,把门开开"

	def auth(self):
		conn = self.request
		# 创建一个随机的32位字节流
		msg = os.urandom(32)
		
		# 把字节流发送给客户端
		conn.send(msg)
		
		# 服务端进行数据校验
		hm = hmac.new(  self.secret_key.encode() , msg  )
		ser_res = hm.hexdigest()
		
		# 服务端接受客户端发送过来的数据结果
		cli_res = conn.recv(1024).decode()
		
		# 进行比对,如果ok 返回True , 反之亦然
		return  True if ser_res == cli_res else False			

	def handle(self):
		if self.auth():
			self.request.send("True".encode())
		else:
			self.request.send("False".encode())

server = socketserver.ThreadingTCPServer( ("127.0.0.1" , 9000)  , MyServer  )
# 开启,让一个端口绑定多个程序;  模块.类.属性 = True
socketserver.TCPServer.allow_reuse_address = True
server.serve_forever()

client.py

# ### 客户端
""" 机器和机器之间的数据直接对接 """
import socket
import hmac

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

def auth(secret_key):
	# 接受服务端发送过来的随机二进制字节流
	msg = sk.recv(32)
	
	# hmac.new(   key(字节流) ,  要加密的内容(字节流)  )
	hm = hmac.new( secret_key.encode() , msg  )
	
	# 返回的是具有固定32位长度的十六进制字符串
	cli_res = hm.hexdigest()
	
	# 把最后计算的结果发送给服务端进行校验
	sk.send(  cli_res.encode() )
	
	# 接受服务端给予的校验结果
	res = sk.recv(1024).decode()
	
	return res
	

# 处理收发数据的逻辑
secret_key = "不开,老妈没回来"
secret_key = "小兔儿乖乖,把门开开"
# 调用授权函数
res = auth(secret_key)

if res == "True":
	print("服务器校验通过")
else:
	print("服务器校验失败")

sk.close()

4. TCP登录

server.py

# ### 服务端
from collections import Iterator,Iterable
import socketserver
import hashlib
import json

class MyServer(socketserver.BaseRequestHandler):

	# 默认没有登录
	sign = False
	
	def get_md5_code(self,usr,pwd):
		hs = hashlib.md5(usr.encode())
		hs.update(pwd.encode())
		return hs.hexdigest()

	def auth(self):
		
		conn = self.request
		# 接受客户端发送过来的数据,通过decode反解成字符串
		res = conn.recv(1024).decode()
		# 通过json把字符串 转换成 字典
		dic = json.loads(res)
		# {'username': 'caijingguan', 'password': '8888', 'operate': 'login'} 
		print(dic , type(dic)) 
		with open("userinfo.data",mode="r",encoding="utf-8") as fp: # fp文件对象是迭代器,一行一行返回数据
			for i in fp:
				# 文件中解析出用户和密码
				usr,pwd = i.strip().split(":")
				if usr == dic["username"] and pwd == self.get_md5_code( dic["username"] , dic["password"] ) : 
					# 自定义返回的字典数据
					dic_msg = {"code":1,"msg":"登录成功"}
					# 把字典 => 字符串
					json_str = json.dumps(dic_msg)
					# 把字符串 => 字节流 发送给客户端
					conn.send( json_str.encode() )
					# 把sign标记从False => True 代表登录成功
					self.sign = True
					break
					
			# 没有找到对应合法的用户名和密码,登录失败
			if self.sign == False:
				dic_msg = {"code":0,"msg":"登录失败"}
				res = json.dumps(dic_msg).encode()
				conn.send(res)		
		
	def handle(self):
		self.auth()

server = socketserver.ThreadingTCPServer( ("127.0.0.1" , 9001) , MyServer )
# 开启,让一个端口绑定多个程序;  模块.类.属性 = True
socketserver.TCPServer.allow_reuse_address = True
server.serve_forever()

"""
# 作业: 完成FTP服务器
(1) 登录 (2) 注册 (3) 上传 (4) 下载
"""

client.py

# ### 客户端
import socket 
import json
"""
pickle => 字节流( 存储数据 )
json   => 字符串( 数据交互 )
"""

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)

# 转化成字节流发送给服务端
sk.send(res.encode())

# 接受服务端响应的数据
res_str = sk.recv(1024).decode()

# 字符串转化成字典
dic = json.loads(res_str)
print(dic , type(dic))
print(dic["msg"])


sk.close()

userinfo.data

		wangwen:bbccc59bedc09e551a394699b44ed9f9
lisi:c79439cf9abcbd6c6d46e45766a9e64a
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值