Hmac模块
其实这个模块类似hashlib模块,它能将一些重要的信息通过算法加密成密文,让信息更具有安全性。
关于hmac加密算法的了解:它的全名是哈希运算消息认证码(Hash-based Message Authentication Code),HMAC利用hash算法,以一个消息M和一个秘钥K作为输入,生成一个定长的消息摘要作为输出。HMAC算法利用已有的hash函数,关键问题是如何使用秘钥。
使用
import hmac # 这个模块和hashlib机制很相似 h = hmac.new(b ' key ' ,b ' msg ' ) # 需要一个秘钥(bytes类型)和你想进行加密的bytes类型数据,前面为随机的key后面为一个消息 print (h.digest()) # 结果拿到一个密文 # b'\x18\xe3T\x8cY\xad@\xdd\x03\x90{z\xee\xe7\x1dg'
检验客户端合法性
如何确定这个客户端是该服务器的合法客户端呢?如果两边实现都讲好了他们的秘钥就可以利用hmac.compare_digest()方法去比较他们最后产生的密文到底是不是相同的,如果是那就是合法的就进行相应的操作,若不合法就直接关闭。
这里介绍一个新的os模块方法urandom(32)
import os print (os.urandom(32)) # 随机生成32位的字节 # b'\xe2\x84:\x93\x82Q9\xff\x9e\x7f\x8a\x97)[\xedn\r\xa8\xf0v\x8b\xc0g\xbd\xe7\xeb\x0e\xa4\xf0\x80\x0c\x16'
利用这种'加盐'的方法我们就能让我们产生的秘钥具有不确定性,更加安全
检验合法的结果 :
Sever:
import socket import hmac from os import urandom secret_key = b ' egg ' # 秘钥 sk = socket.socket() sk.bind(( ' 127.0.0.1 ' ,8090 )) sk.listen() def check_conn(conn): constant = urandom(32 ) conn.send(constant) h = hmac.new(secret_key,constant) # 拿到一个密文对象 sever_digest = h.digest() client_digest = conn.recv(1024 ) return hmac.compare_digest(sever_digest,client_digest) conn,addr = sk.accept() res = check_conn(conn) if res: print ( ' 合法的客户端! ' ) # 合法的客户端! # 进行一系列操作 # conn.close() pass else : print ( ' 不合法的客户端! ' ) conn.close() sk.close()
Client:
import socket import hmac secret_key = b ' egg ' sk = socket.socket() sk.connect(( ' 127.0.0.1 ' ,8090 )) msg = sk.recv(1024 ) h = hmac.new(secret_key,msg) client_digest = h.digest() sk.send(client_digest) sk.close()
那如果这个客户端它并不知道服务端的秘钥或者不知道服务端用的是HMAC进行的加密,那么它的结果很有可能是错误,给我们返回错误的客户端!
Socketsever模块
socketsever模块它能够实现多个客户端之间的交互
基本实现
Sever:
import socketserver class Mysever(socketserver.BaseRequestHandler): # 一般情况下带Base都是作为父类,Request即请求,Handler就是处理 def handle(self): print (self.request.recv(1024).decode( ' utf-8 ' )) # self.request相当于一个conn if __name__ == ' __main__ ' : sever = socketserver.ThreadingTCPServer(( ' 127.0.0.1 ' ,8080),Mysever) # Thread线程 # 在一个程序里正常情况下只会有一个线程 # 一个线程就是调度CPU的最小单位 # 引入线程的概念去实现并发的效果 sever.serve_forever() # 表示我永远启用一个服务
Client:
import socket sk = socket.socket() sk.connect(( ' 127.0.0.1 ' ,8080 )) sk.send( ' hi ' .encode( ' utf-8 ' )) sk.close()
Output:
hi
有socketsever的原因就是我想同时处理多个客户端找我下载的请求,那socketsever只是在底层的基础上做了一层封装,帮我们实现了并发效果,所以没有'clientsever'这个概念,客户端只需要正常启用就好
实现多个客户端交互
Sever:
import socketserver class Mysever(socketserver.BaseRequestHandler): def handle(self): while True: msg = self.request.recv(1024).decode( ' utf-8 ' ) print (msg) info = input( ' <<< ' ).encode( ' utf-8 ' ) self.request.send( ' Sever: ' .encode( ' utf-8 ' ) + info) if __name__ == ' __main__ ' : sever = socketserver.ThreadingTCPServer(( ' 127.0.0.1 ' ,8080 ),Mysever) sever.serve_forever()
Client1:
import socket sk = socket.socket() sk.connect(( ' 127.0.0.1 ' ,8080 )) while True: msg = input( ' <<< ' ).encode( ' utf-8 ' ) sk.send( ' Client1: ' .encode( ' utf-8 ' ) + msg) print (sk.recv(1024).decode( ' utf-8 ' )) sk.close()
Client2:
import socket sk = socket.socket() sk.connect(( ' 127.0.0.1 ' ,8080 )) while True: msg = input( ' <<< ' ).encode( ' utf-8 ' ) sk.send( ' Client2: ' .encode( ' utf-8 ' ) + msg) print (sk.recv(1024).decode( ' utf-8 ' )) sk.close()
Output: