1. 模块 socketserver
网络协议的最底层就是 socket , 基于原有 socket 模块 , 又封装了一层 , 就是 socketserver
socketserver : 为了实现 tcp 协议 server 端的并发
1.1 server 服务端
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()
1.2 client 客户端
import socket
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sk.connect(('127.0.0.1',9000))
# 处理收发数据的逻辑
sk.close()
2.1 server 服务端
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
"""
print(self.request)
self.request <==> conn
<socket.socket fd=4, family=AddressFamily.AF_INET,
type=SocketKind.SOCK_STREAM, proto=0,
laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 49116)>
print(self.client_address)
self.client_address <==> addr ('127.0.0.1', 49116)
"""
conn = self.request
while True:
# 接收数据
msg1 = conn.recv(1024)
msg = msg1.decode('utf-8')
print(msg)
conn.send(msg.upper().encode('utf-8'))
print("handle方法被执行了")
# ThreadingTCPServer(ip端口号,自定义的类)
server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)
# 建立连接,循环调用
server.serve_forever()
2.2 client 客户端
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()
2. hashlib 模块
hashlib 模块是一堆加密算法的集合体 , 哈希算法的加密方式不止一种
http://www.cmd5.com md5解密
应用场景: 在需要校验功能时使用
用户密码 => 加密,解密
相关校验 => 加密,解密
哈希算法也叫摘要算法 , 相同的数据始终得到相同的输出 , 不同的数据得到不同的输出
1. 哈希将不可变的任意长度的数据 , 变成具有固定长度的唯一值
2. 字典的键和集合的值是通过哈希计算存储的 , 存储的数据是散列(无序)
1. 密码加密
import hashlib
import random
# 1. 基本用法
# 1.1 创建一个 md5 算法对象
hm = hashlib.md5()
# 1.2 把要加密的字符串通过 update 更新到 hm 对象中运算
hm.update('123456'.encode('utf-8')) # 里面的数据必须是二进制字节流
# 1.3 获取32位16进制字符串
res = hm.hexdigest()
print(res , len(res))
# 加盐(加key => Xboy_) 加一个关键字配合原字符进行加密,使密码更复杂,不容易被破解
hm = hashlib.md5("Xboy_wangwen".encode())
hm.update("123456".encode('utf-8'))
res = hm.hexdigest()
print(res , len(res))
# 动态加盐
res = str(random.randrange(100000,1000000))
print(res)
hm = hashlib.md5(res.encode("utf-8"))
hm.update("123456".encode())
res = hm.hexdigest()
print(res)
# sha算法
"""
sha 算出来的十六进制的串是40位,加密稍慢,安全性稍高
md5 算出来的十六进制的串是32位,加密很快,安全性稍差
"""
hs = hashlib.sha1()
hs.update("我最是牛逼的tyert$#$^%*trhegdwerdfs".encode())
res = hs.hexdigest()
print(res, len(res))
hs = hashlib.sha512()
hs.update("123456".encode())
res = hs.hexdigest()
print(res , len(res))
# hmac 模块
"""hmac 加密算法更加复杂,不容易破解"""
import hmac
# hmac.new(盐,密码)
key = b"a"
msg = b"123456"
hn = hmac.new(key,msg)
res = hn.hexdigest()
print(res, len(res)) # 32位长度 十六进制的字符串
# 动态加盐
import os
# os.urandom 返回随机的二进制字节流
res = os.urandom(32)
print(res,len(res))
key = os.urandom(32)
msg = b"123"
hn = hmac.new(key,msg)
res = hn.hexdigest()
print(res, len(res))
2. 文件校验
import hashlib
import os
"""
mode => r read(数字->字符个数)
mode => rb read(数字->字节个数)
字节的个数 <=> 文件的大小
"""
# (1) 针对于小文件进行内容校验
def check_md5(filename):
hs = hashlib.md5()
with open(filename,mode="rb") as fp:
hs.update(fp.read())
return hs.hexdigest()
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)
# 方法一
def check_md5(filename):
hs = hashlib.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:
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)
3. 服务端的合法性校验
1. server 服务端
# 服务端 (支付宝)
import socket
import os
import hmac
def auth(conn,secret_key):
# 随机产生32位的二进制字节流
msg = os.urandom(32)
conn.send(msg)
hn = hmac.new(secret_key.encode('utf-8'),msg)
res_server = hn.hexdigest()
print(res_server)
# 服务端接收客户端发送过来的数据进行验证
res_client = conn.recv(1024).decode('utf-8')
if res_client == res_server:
print('你是合法的服务端用户')
return True
else:
print('不是合法的服务端用户')
return Flase
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()
2. client 客户端
# 客户端 (公司)
import socket
import hmac
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 = '芝麻开门'
auth(sk,secret_key)
# 在验证成功之后,接收服务端发来的验证码
res = sk.recv(1024).decode('utf-8')
print(res)
sk.close()
4. tcp协议登录
1. server 服务端
import socket
import hashlib
import json
def get_md5_code(usr,pwd):
hs = hashlib.md5(usr.encode())
hs.update(pwd.encode())
return hs.hexdigest()
sk = socket.socket()
sk.bind(("127.0.0.1",9000))
sk.listen()
conn,addr = sk.accept()
# 处理收发数据的逻辑
msg = conn.recv(1024).decode()
# 把反解之后的字符串恢复成原来的数据格式变成字典
dic = json.loads(msg)
print(dic)
sign = False
with open('user_info.txt',mode='r',encode='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}
msg = json.dumps(res).encode('utf-8')
conn.send(msg)
sign = True
break
if sign == False:
# 发送错误的状态码
res = {'code':0}
msg = json.dumps(res).encode()
conn.send(msg)
conn.close()
sk.close()
2. client 客户端
import socket
import json
sk.socket.socket()
sk.connect(('127.0.0.1',9000))
# 处理收发数据的逻辑
usr = input('请输入您的用户名: ').strip()
pwd = input('请输入您的密码: ').strip()
dic = {'username':usr,'password':pwd,'operate':'login'}
# 先通过json变成字符串
res = json.dumps(dic)
# json 字符串 -> 字节流
msg = res.encode()
# 把字节流发送给服务端
sk.send(msg)
# 接收服务端发送过来的数据
res = sk.recv(1024).decode()
dic_code = json.loads(res)
if dic_code['code']:
print('恭喜您~登陆成功!')
else:
print('I am so sorry ~ 登陆失败')
sk.close()