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