1. 程式人生 > >網路程式設計中客戶端連結的合法性,socketserver模組

網路程式設計中客戶端連結的合法性,socketserver模組

客戶端連結的合法性

 

驗證合法性:
  首先,我們來探討一下,什麼叫驗證合法性, 舉個例子:有一天,我開了一個socket服務端,只想讓咱們這個班的同學使用,但是有一天,
隔壁班的同學過來問了一下我開的這個服務端的ip和埠,然後他是不是就可以去連線我了啊,那怎麼辦,我是不是不想讓他連線我啊,我需要驗證一下你的身份,
這就是驗證連線的合法性,再舉個例子,就像我們上面說的你的windows系統是不是連線微軟的時間伺服器來獲取時間的啊,你的mac能到人家微軟去獲取時間嗎,你願意,
人家微軟還不願意呢,對吧,那這時候,你每次連線我來獲取時間的時候,我是不是就要驗證你的身份啊,也就是你要帶著你的系統資訊,我要判斷你是不是我微軟的windows,

對吧,如果是mac,我是不是不讓你連啊,這就是連接合法性。如果驗證你的連線是合法的,那麼如果我還要對你的身份進行驗證的需求,也就是要驗證使用者名稱和密碼,那麼我們還需要進
行身份認證。連線認證>>身份認證>>ok你可以玩了。
客戶端連結認證功能實現:
驗證合法性連線的服務端:
 1 secret_key=b'Jedan has a big key!'
 2 def conn_auth(conn):
 3     '''
 4     認證客戶端連結
 5     :param conn:
 6     :return:
 7     '''
 8     print
('開始驗證新連結的合法性') 9 msg=os.urandom(32)#生成一個32位元組的隨機字串 10 conn.sendall(msg) 11 h=hmac.new(secret_key,msg) 12 digest=h.digest() 13 respone=conn.recv(len(digest)) 14 return hmac.compare_digest(respone,digest) 15 16 def data_handler(conn,bufsize=1024): 17 if not conn_auth(conn):
18 print('該連結不合法,關閉') 19 conn.close() 20 return 21 print('連結合法,開始通訊') 22 while True: 23 data=conn.recv(bufsize) 24 if not data:break 25 conn.sendall(data.upper()) 26 27 def server_handler(ip_port,bufsize,backlog=5): 28 ''' 29 只處理連結 30 :param ip_port: 31 :return: 32 ''' 33 tcp_socket_server=socket(AF_INET,SOCK_STREAM) 34 tcp_socket_server.bind(ip_port) 35 tcp_socket_server.listen(backlog) 36 while True: 37 conn,addr=tcp_socket_server.accept() 38 print('新連線[%s:%s]' %(addr[0],addr[1])) 39 data_handler(conn,bufsize) 40 41 if __name__ == '__main__': 42 ip_port=('127.0.0.1',9999) 43 bufsize=1024 44 server_handler(ip_port,bufsize)
驗證合法性的連線的客戶端:
 1 from socket import *
 2 import hmac,os
 3 
 4 secret_key=b'Jedan has a big key!'
 5 def conn_auth(conn):
 6     '''
 7     驗證客戶端到伺服器的連結
 8     :param conn:
 9     :return:
10     '''
11     msg=conn.recv(32)
12     h=hmac.new(secret_key,msg)
13     digest=h.digest()
14     conn.sendall(digest)
15 
16 def client_handler(ip_port,bufsize=1024):
17     tcp_socket_client=socket(AF_INET,SOCK_STREAM)
18     tcp_socket_client.connect(ip_port)
19 
20     conn_auth(tcp_socket_client)
21 
22     while True:
23         data=input('>>: ').strip()
24         if not data:continue
25         if data == 'quit':break
26 
27         tcp_socket_client.sendall(data.encode('utf-8'))
28         respone=tcp_socket_client.recv(bufsize)
29         print(respone.decode('utf-8'))
30     tcp_socket_client.close()
31 
32 if __name__ == '__main__':
33     ip_port=('127.0.0.1',9999)
34     bufsize=1024
35     client_handler(ip_port,bufsize)

 

介紹程式碼中使用的兩個方法:
1、os.urandom(n)
     其中os.urandom(n) 是一種bytes型別的隨機生成n個位元組字串的方法,而且每次生成的值都不相同。再加上md5等加密的處理,就能夠成內容不同長度相同的字串了。
使用方法:
1 import os
2 from hashlib import md5
3 
4 for i in range(10):
5     print (md5(os.urandom(24)).hexdigest())

 

2、hmac: 我們完全可以用hashlib來實現,但是學個新的嗎,沒什麼不好的,這個操作更方便一些。
    Python自帶的hmac模組實現了標準的Hmac演算法,我們首先需要準備待計算的原始訊息message,隨機key,雜湊演算法,這裡採用MD5.
使用hmac的程式碼如下:
1 import hmac
2 
3 message = b'Hello world'
4 key = b'secret'
5 h = hmac.new(key, message, digestmod='MD5')
6 print(h.hexdigest())
比較兩個密文是否相同,可以用hmac.compare_digest(密文、密文),然會True或者False。


socketserver模組實現併發
服務端:
 1 #引入模組
 2 import socketserver
 3 #自己寫一個類,類名自己隨便定義,然後繼承socketserver這個模組裡面的
 4 class Myserver(socketserver.BaseRequestHandler):
 5     # 寫一個handle方法,必須叫這個名字
 6     def handle(self):
 7         while 1:  #迴圈進行讀取回復
 8             from_client_msg = self.request.recv(1024)  # self.request = conn 接收訊息
 9             print(from_client_msg.decode('utf-8'))    #列印客戶端訊息
10             msg = input('服務端說:')
11             self.request.send(msg.encode('utf-8'))   #發訊息
12 #thread 執行緒,現在只需要簡單理解執行緒,彆著急,後面很快就會講到啦,看下面的圖
13 if __name__ == '__main__':
14     #使用socketserver的ThreadingTCPServer這個類,將IP和埠的元祖傳進去,還需要將上面咱們自己定義的類傳進去,得到一個物件,相當於我們通過它進行了bind、listen
15     ip_port = ('127.0.0.1',8001)
16     server = socketserver.ThreadingTCPServer(ip_port,Myserver)
17     #使用我們上面這個類的物件來執行serve_forever(),方法,他的作用就是說,我的服務一直開啟著,就像京東一樣,不能關閉網站,對吧,並且serve_forever(),幫我們進行了accept
18     server.serve_forever()
客戶端:
 1 # 匯入socket
 2 import socket
 3 
 4 # 建立client客戶端物件
 5 client = socket.socket()
 6 # 通過connect連線伺服器
 7 client.connect(('127.0.0.1', 8001))
 8 # 迴圈連線
 9 while 1:
10     msg = input('客戶端說>>>')
11     # 訊息傳送至服務端
12     client.send(msg.encode('utf-8'))
13     # 接受服務端訊息
14     from_server_msg = client.recv(1024)
15     # 列印服務端回覆訊息
16     print(from_server_msg.decode('utf-8'))