# websocket實現原理 ''' 1.服務端開啓socket,監聽ip和端口 2.客戶端發送鏈接請求(帶上ip和端口) 3.服務端容許鏈接 4.客戶端生成一個隨機字符串,和magic string組合進行一個sha1加密,加密。並將隨機字符串發送給服務端 5.而後服務端也要用相同的方式進行加密。 6.而後服務端將加密以後的密串返回給客戶端 7.客戶端將服務端返回的密串和本身加密以後的密串進行比對,若是同樣,說明遵循一樣的協議。若是不同,就無法玩了····· ''' import socket import base64 import hashlib from pprint import pprint def get_headers(data): """ 將請求頭格式化成字典 :param data: :return: """ header_dict = {} data = str(data, encoding='utf-8') header, body = data.split('\r\n\r\n', 1) header_list = header.split('\r\n') for i in range(0, len(header_list)): if i == 0: if len(header_list[i].split(' ')) == 3: header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ') else: k, v = header_list[i].split(':', 1) header_dict[k] = v.strip() return header_dict server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('localhost', 8080)) server.listen(5) # 等待用戶鏈接 conn, addr = server.accept() # 握手消息 content = conn.recv(8096) ''' >>> print(content) b'GET / HTTP/1.1\r\nHost: localhost:8080\r\nConnection: Upgrade\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nUpgrade: websocket\r\nOrigin: http://localhost:63342\r\nSec-WebSocket-Version: 13\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: uuid=81a68694c772e0c62d4a5a3c256fe3e0; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2216453a8bf2bbe-09a40e8e58a866-5e442e19-1fa400-16453a8bf2c745%22%7D; Hm_lvt_2af69bc2b378fb58ae04ed2a04257ed1=1530411925; Pycharm-bdfc5fce=a920e49d-da4e-4d2f-a76e-17acfacc6462\r\nSec-WebSocket-Key: 1y6WpsSgfF80wqi3HpmrqQ==\r\nSec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n' ''' # 獲取請求頭 headers = get_headers(content) ''' >>>pprint(headers) {'Cache-Control': 'no-cache', 'Connection': 'Upgrade', 'Cookie': 'Pycharm-bdfc5fce=a920e49d-da4e-4d2f-a76e-17acfacc6462', 'Host': 'localhost:8080', 'Origin': 'http://localhost:63342', 'Sec-WebSocket-Key': 'RRGDeYeYSGEP9eHy85u8oQ==', 'Sec-WebSocket-Version': '13', 'Upgrade': 'websocket', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) ' 'like Gecko', 'method': 'GET', 'protocol': 'HTTP/1.1', 'url': '/'} ''' # 規定:魔法字符串就叫這個 magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" # 獲取隨機密串,並將其與魔法字符串組合 value = headers["Sec-WebSocket-Key"] + magic_string # 進行加密,規定,只能按照此加密方式 hash_str = base64.b64encode(hashlib.sha1(bytes(value, encoding='utf-8')).digest()) response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \ "Upgrade:websocket\r\n" \ "Connection: Upgrade\r\n" \ "Sec-WebSocket-Accept: %s\r\n" \ "WebSocket-Location: ws://%s%s\r\n\r\n" # 獲取握手消息,組合魔法字符串,進行sha1加密 # 發送給客戶端 response_str = response_tpl % (str(hash_str, encoding='utf-8'), headers['Host'], headers['url']) conn.send(bytes(response_str, encoding='utf-8'))
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> ws = new WebSocket("ws://localhost:8080/"); //若是鏈接成功,會打印下面這句話,不然不會打印 ws.onopen = function () { console.log('鏈接成功') } </script> </body> </html>