1. 程式人生 > >驗證客戶端鏈接以及socketserver模塊

驗證客戶端鏈接以及socketserver模塊

超時 dal gif ads sendto utf blocking 文件 循環

技術分享圖片
 1 服務端套接字函數
 2 s.bind()    綁定(主機,端口號)到套接字
 3 s.listen()  開始TCP監聽
 4 s.accept()  被動接受TCP客戶的連接,(阻塞式)等待連接的到來
 5 
 6 客戶端套接字函數
 7 s.connect()     主動初始化TCP服務器連接
 8 s.connect_ex()  connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
 9 
10 公共用途的套接字函數
11 s.recv()            接收TCP數據
12 s.send()            發送TCP數據
13 s.sendall()         發送TCP數據
14 s.recvfrom() 接收UDP數據 15 s.sendto() 發送UDP數據 16 s.getpeername() 連接到當前套接字的遠端的地址 17 s.getsockname() 當前套接字的地址 18 s.getsockopt() 返回指定套接字的參數 19 s.setsockopt() 設置指定套接字的參數 20 s.close() 關閉套接字 21 22 面向鎖的套接字方法 23 s.setblocking() 設置套接字的阻塞與非阻塞模式 24 s.settimeout() 設置阻塞套接字操作的超時時間
25 s.gettimeout() 得到阻塞套接字操作的超時時間 26 27 面向文件的套接字的函數 28 s.fileno() 套接字的文件描述符 29 s.makefile() 創建一個與該套接字相關的文件
socket的更多用法介紹

驗證客戶端連接的合法性

端口的範圍:0-65535

技術分享圖片
 1 #server
 2 import os
 3 import socket
 4 import hmac
 5 def auth(conn):
 6     msg = os.urandom(32)    #生成一個隨機字符串
 7     conn.send(msg)              #
發送到client端 8 result = hmac.new(secret_key, msg) #處理這個字符串,得到一個結果 9 client_digest = conn.recv(1024) #接收client端處理的結果 10 if result.hexdigest() == client_digest.decode(utf-8): 11 print(合法的連接) #對比成功可以繼續通信 12 return True 13 else: 14 print(不合法的連接) #不成功 close 15 return False 16 secret_key = bwangwang 17 sk = socket.socket() 18 sk.bind((127.0.0.1, 8520)) 19 sk.listen() 20 conn, addr = sk.accept() 21 if auth(conn): 22 print(conn.recv(1024)) #可以正常與client端進行通信了 23 conn.close() 24 else: 25 conn.close() 26 sk.close() 27 28 #client 29 import hmac 30 import socket 31 def auth(sk): 32 msg = sk.recv(32) 33 result = hmac.new(key, msg) 34 res = result.hexdigest() 35 sk.send(res.encode(utf-8)) 36 key =bwangwang 37 sk = socket.socket() 38 sk.connect((127.0.0.1, 8520)) 39 auth(sk) 40 sk.send(bupload) #正常的和server端進行通信 41 sk.close()
驗證

主要用於內部的驗證,對登陸者進行簡單的驗證

socketserver 模塊

TCP協議下,server端可以與多個client端連接

技術分享圖片
 1 #server端
 2 import socketserver
 3 #tcp協議的server端不需要導入socket
 4 class Myserver(socketserver.BaseRequestHandler):
 5     def handle(self):
 6         conn = self.request
 7         while True:
 8             msg = input(>>>)
 9             conn.send(msg.encode(utf-8))
10             re_msg = conn.recv(1024)
11             print(re_msg.decode(utf-8))
12 
13 socketserver.TCPServer.allow_reuse_address = True
14 # 設置allow_reuse_address允許服務器重用地址
15 server = socketserver.ThreadingTCPServer((127.0.0.1, 8520),Myserver)
16 # 創建一個server, 將服務地址綁定到127.0.0.1:8520
17 server.serve_forever()
18 # 讓server永遠運行下去,除非強制停止程序
19 
20 #client
21 import socket
22 sk = socket.socket()
23 sk.connect((127.0.0.1, 8520))
24 while True:
25     ret = sk.recv(1024)
26     print(ret.decode(utf-8))
27     msg = input(>>>)
28     sk.send(msg.encode(utf-8))
29     if msg == q:
30         break
31 sk.close()
sockterserver

########################################################

基於tcp的套接字,關鍵就是兩個循環,一個鏈接循環,一個通信循環

socketserver模塊中分兩大類:server類(解決鏈接問題)和request類(解決通信問題)

server類:

技術分享圖片

request類:

技術分享圖片

繼承關系:

技術分享圖片

技術分享圖片

技術分享圖片

以下述代碼為例,分析socketserver源碼:

ftpserver=socketserver.ThreadingTCPServer((‘127.0.0.1‘,8080),FtpServer)
ftpserver.serve_forever()

查找屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer

  1. 實例化得到ftpserver,先找類ThreadingTCPServer的__init__,在TCPServer中找到,進而執行server_bind,server_active
  2. 找ftpserver下的serve_forever,在BaseServer中找到,進而執行self._handle_request_noblock(),該方法同樣是在BaseServer中
  3. 執行self._handle_request_noblock()進而執行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然後執行self.process_request(request, client_address)
  4. 在ThreadingMixIn中找到process_request,開啟多線程應對並發,進而執行process_request_thread,執行self.finish_request(request, client_address)
  5. 上述四部分完成了鏈接循環,本部分開始進入處理通訊部分,在BaseServer中找到finish_request,觸發我們自己定義的類的實例化,去找__init__方法,而我們自己定義的類沒有該方法,則去它的父類也就是BaseRequestHandler中找....

源碼分析總結:

基於tcp的socketserver我們自己定義的類中的

  1.   self.server即套接字對象
  2.   self.request即一個鏈接
  3.   self.client_address即客戶端地址

基於udp的socketserver我們自己定義的類中的

  1.   self.request是一個元組(第一個元素是客戶端發來的數據,第二部分是服務端的udp套接字對象),如(b‘adsf‘, <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=(‘127.0.0.1‘, 8080)>)
  2.   self.client_address即客戶端地址

驗證客戶端鏈接以及socketserver模塊