铁乐学Python_Day35_Socket模块3和hmac模块
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                铁乐学Python_Day35_Socket模块3和hmac模块
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                驗證客戶端鏈接的合法性
如果你想在分布式系統中實現一個簡單的客戶端鏈接認證功能,又不像SSL那么復雜,
 那么可以利用hmac+加鹽的方式來實現。
例1:簡單的服務端如下
#!/usr/bin/env python
# _*_ coding: utf-8 _*_import os
import socket
import hmacsecret_key = '老衲洗頭用飄柔'.encode('utf-8')
server = socket.socket()
server.bind(('127.0.0.1', 9527))
server.listen()
while True:try:conn, addr = server.accept()random_bytes = os.urandom(32)conn.send(random_bytes)hmac_obj = hmac.new(key=secret_key, msg=random_bytes)ret = hmac_obj.hexdigest()print(hmac_obj.hexdigest())msg = conn.recv(1024).decode('utf-8')if msg == ret:print('是合法的客戶端')else:print('不是合法的客戶端')conn.close()finally:server.close()break客戶端如下:
#!/usr/bin/env python
# _*_ coding: utf-8 _*_import socket
import hmacsecret_key = '老衲洗頭用飄柔'.encode('utf-8')
client = socket.socket()
client.connect(('127.0.0.1', 9527))urandom = client.recv(1024)
hmac_obj = hmac.new(key=secret_key, msg=urandom)
client.send(hmac_obj.hexdigest().encode('utf-8'))
print('--------')
client.close()效果如下:
33e40f5f66b2e9b2867a7862d02fba9d
是合法的客戶端。例2:TCP時間戳服務器驗證
#!/usr/bin/env python
# _*_ coding: utf-8 _*_import os
import hmac
from socket import *
from time import ctime'''
socket tcp時間戳服務端,利用hmac模塊加鹽驗證客戶端連接的合法性
'''# 加鹽
secret_key = '芝麻開門'.encode('utf-8')def conn_auth(conn):'''認證客戶端鏈接:param conn: 客戶端鏈接:return: True or False'''print('開始驗證新鏈接的合法性')# os模塊生成隨機32位字符串,用于發送給客戶端驗證ustr = os.urandom(32)conn.sendall(ustr)# 生成密鑰 hmac加鹽+32位隨機字符串cipher = hmac.new(secret_key, ustr).digest()# 接收客戶端發送過來的密鑰,長度和這邊生成的應當一致result = conn.recv(len(cipher))# compare 兩相比較,一致返回true,否則為falsereturn hmac.compare_digest(result, cipher)def data_handler(conn,bufsize=1024):# 如果驗證不通過if not conn_auth(conn):print('鏈接非法,關閉')conn.close()returnprint('鏈接已通過驗證,開始通信')while True:data = conn.recv(bufsize)if not data:breakdata = '[%s] %s' % (ctime(), data.decode('utf-8'))conn.sendall(data.encode('utf-8'))conn.close()def server_handler(host,port,bufsize=1024,num=5):'''socket tcp服務端設置:param host: 主機名或ip地址:param port: 端口號:param bufsize: 緩沖區大小,默認1024:param num: 偵聽最大客戶端,默認5位:return: '''tcpss = socket(AF_INET, SOCK_STREAM)tcpss.bind((host,port))tcpss.listen(num)while True:conn, addr = tcpss.accept()print('新連接[%s:%s]' % (addr[0], addr[1]))data_handler(conn,bufsize)if __name__ == '__main__':host = 'localhost'port = 9527server_handler(host, port)TCP時間戳客戶端:
#!/usr/bin/env python
# _*_ coding: utf-8 _*_'''
socket tcp時間戳客戶端,利用hmac模塊加鹽驗證客戶端連接的合法性
'''import os
import hmac
from socket import *secret_key = '芝麻開門'.encode('utf-8')def conn_auth(conn):'''驗證客戶端到服務器的鏈接:param conn: 鏈接:return: True or False'''# 客戶端接收32位隨機字節ustr = conn.recv(32)# hmac加鹽加密文得出最終密鑰并發送回服務端cipher = hmac.new(secret_key, ustr).digest()conn.sendall(cipher)def client_handler(host,port,bufsize=1024):tcpsc = socket(AF_INET, SOCK_STREAM)tcpsc.connect((host, port))conn_auth(tcpsc)while True:data = input('>>>').strip()if not data:continueif data == 'quit':breaktcpsc.sendall(data.encode('utf-8'))result = tcpsc.recv(bufsize)print(result.decode('utf-8'))tcpsc.close()if __name__ == '__main__':host = 'localhost'port = 9527bufsize = 1024client_handler(host, port, bufsize)效果:
服務端:
D:\PortableSoft\Python35\python.exe E:/Python/重要的代碼/socket_hmac驗證合法連接/tcpss.py
新連接[127.0.0.1:57600]
開始驗證新鏈接的合法性
鏈接已通過驗證,開始通信客戶端:
D:\PortableSoft\Python35\python.exe E:/Python/重要的代碼/socket_hmac驗證合法連接/tcpsc.py
>>>time
[Thu May 10 22:00:19 2018] time
>>>也許豬的身體不優美,長鼻短尾,但是別人不可天空里高飛
[Thu May 10 22:01:10 2018] 也許豬的身體不優美,長鼻短尾,但是別人不可天空里高飛
>>>socketserver
SocketServer是標準庫中的一個高級模塊(python3.x中重命名為socketserver),
 它的目標是簡化很多樣板代碼,它們是創建網絡客戶端和服務器所必需的代碼。
 這個模塊中有為你創建的各種各樣的類,如下表所示:
除了為你隱藏了實現細節之外,另一個不同之處是,我們現在使用類來編寫應用程序,
 以面向對象的方式處理事務有助于組織數據,以及邏輯性地將功能放在正確的地方。
 你還會注意到,應用程序現在是事件驅動的,這意味著只有在系統中的事件發生時,它們才會工作。
事件包括消息的發送和接收。
事實上,你會看到類定義只包括一個用來接收客戶端消息的事件處理程序。
 所有其它的功能都來自使用的SocketServer類。
 在原始服務器循環中,我們阻塞等待請求,當接收到請求時就對其提供服務,然后繼續等待。
 在此處的服務器循環中,并非在服務器中創建代碼,而是定義一個處理程序,
 這樣當服務器接收到一個傳入的請求時,服務器就可以調用你的函數。
創建SocketServer TCP服務器
#!/usr/bin/env python
# _*_ coding: utf-8 _*_'''
通過使用socketserver類、TCPServer和StreamRequesthandler,該腳本創建了一個時間戳TCP服務器。
'''from socketserver import (TCPServer as TCP, StreamRequestHandler as SRH)
from time import ctimeHOST = '127.0.0.1'
PORT = 9527
ADDR = (HOST, PORT)class MyRequestHandler(SRH):# 重寫handle方法,該方法在基類Request中默認情況下沒有任何行為(pass)
# 但當接收到一個客戶端的消息時,它就會調用handle()方法,因此得重寫進行處理。def handle(self):print('...connected from:', self.client_address)# StreamRequsetHandler將輸入和輸出套接字看作類似文件的對象# 因此可以使用readline()獲取客戶端消息,當然此時客戶端要約定消息附帶\n換行符data = '[%s] %s' % (ctime(), self.rfile.readline().decode('utf-8'))# 同理,視作文件對象,使用write()將字符串發送回客戶端self.wfile.write(data.encode('utf-8'))tcpServ = TCP(ADDR, MyRequestHandler)
print('waiting for connection...')
# 注:是serve,而不是server;forever為無限循環地等待并服務于客戶端請求。
tcpServ.serve_forever()創建SocketServer TCP客戶端
#!/usr/bin/env python
# _*_ coding: utf-8 _*_from socket  import *HOST = 'localhost'
PORT = 9527
BUFSIZ = 1024
ADDR = (HOST, PORT)while True:'''和之前socker普通的tcp客戶端從輸入才開始循環不同,sockerserver請求處理程序的默認行為是接受連接、獲取請求,然后關閉連接。由于這個原因,我們不能在應用程序整個執行過程中都保持連接,因此每次向服務器發送消息時,都需要創建一個新的套接字。'''tcpCliSock = socket(AF_INET, SOCK_STREAM)tcpCliSock.connect(ADDR)data = input('>>>')if not data:break'''這里使用的處理程序對待套接字通信就像是文件一樣,所以必須發送行終止符(回車和換行符)。而服務器只是保留并重用這里發送的終止符。'''data = '%s\r\n' % datatcpCliSock.send(data.encode('utf-8'))resu = tcpCliSock.recv(BUFSIZ)if not resu:break# 加strip()處理掉換行符print(resu.decode('utf-8').strip())tcpCliSock.close()運行服務端和客戶端后效果如下:
client端:
>>>百變星君
[Wed May  9 20:44:11 2018] 百變星君
>>>大圣娶親
[Wed May  9 20:44:22 2018] 大圣娶親
>>>
server端:
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 53286)
----------------------------------------
...connected from: ('127.0.0.1', 53397)
...connected from: ('127.0.0.1', 53398)
...connected from: ('127.0.0.1', 53399)另一種不看成文件操作的支持并發連接的TCP時間戳服務器和客戶端如下:
socketserver TCP時間戳服務器
#!/usr/bin/env python
# _*_ coding: utf-8 _*_import socketserver
from time import ctime# 并發編程
class MyServer(socketserver.BaseRequestHandler):def handle(self):print('...連接來自:', self.client_address)msg = self.request.recv(1024)msg = '[%s] %s' % (ctime(), msg.decode('utf-8'))print(msg)self.request.send(msg.encode('utf-8'))if __name__ == '__main__':# 支持重用端口和Ipsocketserver.TCPServer.allow_reuse_address = True# ThreadingTCPServer 支持線程功能server = socketserver.ThreadingTCPServer(('127.0.0.1', 9527), MyServer)print('等待連接...')server.serve_forever()socketserver TCP時間戳客戶端
#!/usr/bin/env python
# _*_ coding: utf-8 _*_import socketwhile True:client = socket.socket()client.connect(('127.0.0.1', 9527))data = input('>>>')if not data:breakclient.send(data.encode('utf-8'))resu = client.recv(1024)if not resu:breakprint(resu.decode('utf-8'))client.close()運行效果如下:
第一個client端:
>>>哆啦A夢
[Wed May  9 20:59:14 2018] 哆啦A夢
>>>蠟筆小新
[Wed May  9 20:59:27 2018] 蠟筆小新
>>>超人迪加
[Wed May  9 21:00:13 2018] 超人迪加
>>>
第二個client端:
>>>銀河唯一的秘密
[Wed May  9 20:59:50 2018] 銀河唯一的秘密
>>>護衛人類,挽救地球,看守這宇宙
[Wed May  9 21:00:35 2018] 護衛人類,挽救地球,看守這宇宙
>>>
socketserver服務端:
等待連接...
...連接來自: ('127.0.0.1', 53505)
[Wed May  9 20:59:14 2018] 哆啦A夢
...連接來自: ('127.0.0.1', 53506)
[Wed May  9 20:59:27 2018] 蠟筆小新
...連接來自: ('127.0.0.1', 53507)
...連接來自: ('127.0.0.1', 53508)
[Wed May  9 20:59:50 2018] 銀河唯一的秘密
...連接來自: ('127.0.0.1', 53509)
[Wed May  9 21:00:13 2018] 超人迪加
...連接來自: ('127.0.0.1', 53510)
[Wed May  9 21:00:35 2018] 護衛人類,挽救地球,看守這宇宙
...連接來自: ('127.0.0.1', 53514)end
參考:
http://www.cnblogs.com/Eva-J/
 《python核心編程第四版》
轉載于:https://www.cnblogs.com/tielemao/p/9022939.html
總結
以上是生活随笔為你收集整理的铁乐学Python_Day35_Socket模块3和hmac模块的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 有红色盖章的合同照片,是扫描仪的高清、还
- 下一篇: 方便面桶装康师傅多少钱一桶?
