鐵樂學Python_Day35_Socket模塊3和hmac模塊

来源:https://www.cnblogs.com/tielemao/archive/2018/05/11/9022939.html
-Advertisement-
Play Games

驗證客戶端鏈接的合法性 如果你想在分散式系統中實現一個簡單的客戶端鏈接認證功能,又不像SSL那麼複雜, 那麼可以利用hmac+加鹽的方式來實現。 SocketServer是標準庫中的一個高級模塊(python3.x中重命名為socketserver), 它的目標是簡化很多樣板代碼,它們是創建網路客... ...


驗證客戶端鏈接的合法性

如果你想在分散式系統中實現一個簡單的客戶端鏈接認證功能,又不像SSL那麼複雜,
那麼可以利用hmac+加鹽的方式來實現。

1:簡單的服務端如下
#!/usr/bin/env python
# _*_ coding: utf-8 _*_

import os
import socket
import hmac

secret_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 hmac

secret_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,否則為false
    return hmac.compare_digest(result, cipher)

def data_handler(conn,bufsize=1024):
    # 如果驗證不通過
    if not conn_auth(conn):
        print('鏈接非法,關閉')
        conn.close()
        return
    print('鏈接已通過驗證,開始通信')
    while True:
        data = conn.recv(bufsize)
        if not data:break
        data = '[%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 = 9527
    server_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:continue
        if data == 'quit':break

        tcpsc.sendall(data.encode('utf-8'))
        result = tcpsc.recv(bufsize)
        print(result.decode('utf-8'))

    tcpsc.close()

if __name__ == '__main__':
    host = 'localhost'
    port = 9527
    bufsize = 1024
    client_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 ctime

HOST = '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' % data
    tcpCliSock.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__':
    # 支持重用埠和Ip
    socketserver.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 socket

while True:
    client = socket.socket()
    client.connect(('127.0.0.1', 9527))
    data = input('>>>')
    if not data:
        break
    client.send(data.encode('utf-8'))
    resu = client.recv(1024)
    if not resu:
        break
    print(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核心編程第四版》


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 模板模式和鉤子函數 一.什麼是模板模式? 定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變一個演算法的結構就能重新定義該演算法的某些特定步驟,模板模式屬於設計模式中的行為模式。 二.如何實現模板模式? 三.模板模式的實現要素? 準備一個抽象基類,將部分邏輯以具體方法的形式 ...
  • 參加工作 關於從學生到職場的轉變與心態起伏,已然有許多文筆好的朋友感嘆過,我想自己作為一個平凡的人,相較他人也不會有更為特別的感受,自然也就不值當多說。只簡單聊聊自身的情況,1月份畢業於非電腦專業,3月底檔案上的職業欄從 變成了 手動滑稽,編程功底相比電腦專業的各位前輩有較大差距,但這就是我職業 ...
  • 我們成功書寫了HelloWorld後,又深入瞭解了main函數,提到過main並非是關鍵字,可什麼又是關鍵字呢?這其實就是這章要研究的內容,本節研究關鍵字與標識符,在標識符中我們也會講解一下Java中的駝峰命名; 1.1 關鍵字 在Hello World中,我們發現其中有很多單詞是固定的,這其實就是 ...
  • 最近也是挺煩的,博客園做為程式員的家園,其實不假。雖然現在寫出的隨筆,看的人少。就當自娛自樂了。煩惱就是矛盾引起的,人很多想法都會被外界環境影響。比如一個思考很久的決定,當事情真發生時,考慮過多,受到外界環境的影響就改變了。 面試真的靠技巧,雖然你很NB,但是面試官不知道,不給你機會,也是白搭。真正 ...
  • JSPs /admin/* BASIC ...
  • 單體應用架構 架構總感覺理我很遠,有時候感覺很迷茫。今天起我把我認識到的三種架構寫出來,一是希望沉澱一下自己所學的東西,二是希望有人能指出我的不足指出,向大家學習。 第一篇 單體應用架構我會總結出單體架構的優缺點,和一般我在經歷過的項目中單體架構所用到的技術,以及我需掌握的知識。 第二篇 垂直應用架 ...
  • 課程是按照真實企業級開發項目流程進行講解,通過學習此課程可以體會到真實的大型大數據項目開發流程,學完此課程可以熟練掌握大數據技術,java web技術,docker虛擬化技術,分散式技術,緩存技術,linux等。 ...
  • 雙擊 勾上藍色保存 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...