python之WebSocket的開發
## websocket.py
import socket import struct import hashlib,base64 import threading,random #執行緒,套接字,雜湊表,隨機數 #存放連結客戶fd,元組 connectionlist = {} #傳送指定的訊息 def sendMessage(message): #對全域性變數的引用 global connectionlist #向客戶端集合中每個成員傳送訊息 # %:字串合成 # ,:字串疊加 for connection in connectionlist.values(): connection.send("\x00%s\xFF" % message) #刪除連線,從集合中刪除連線物件item(建立一個連線追加到連線中) def deleteconnection(item): global connectionlist del connectionlist['connection'+item] #定義WebSocket物件(基於執行緒物件) class WebSocket(threading.Thread): # def __init__(self,conn,index,name,remote, path="/"): #初始化執行緒 threading.Thread.__init__(self) #初始化資料,全部儲存到自己的資料結構中self self.conn = conn self.index = index self.name = name self.remote = remote self.path = path self.buffer = "" #執行執行緒 def run(self): #Log輸出,套接字index啟動 print 'Socket%s Start!' % self.index headers = {} #Socket是否握手的標誌,初始化為false. self.handshaken = False #迴圈執行如下邏輯 while True: #如果沒有進行握手 if self.handshaken == False: #Log輸出,Socket x開始與遠端客戶y進行握手過程 print 'Socket%s Start Handshaken with %s!' % (self.index,self.remote) #從客戶端接受1kb資料,存放到buffer中 self.buffer += self.conn.recv(1024) #如果接受資料中有\r\n\r\n的標誌 if self.buffer.find('\r\n\r\n') != -1: #按照這種標誌分割一次,結果為:header data(網頁的解析) #再對header 和 data部分進行單獨的解析 header, data = self.buffer.split('\r\n\r\n', 1) #對header進行分割後,取出後面的n-1個部分 for line in header.split("\r\n")[1:]: #逐行的解析Request Header資訊(Key,Value) key, value = line.split(": ", 1) #然後存放在一個Hash表中,方便訪問 headers[key] = value #人為定義Location的item的資訊 #構造location:ws://localhost/path ? headers["Location"] = "ws://%s%s" %(headers["Host"], self.path) print "Location:",headers["Location"] print "headers:",headers #取出其中兩項資訊key1 key2 #key1 = headers["Sec-WebSocket-Key1"] #key2 = headers["Sec-WebSocket-Key2"] #Header解析完畢後,分析data部分 #如果data部分長度小於8的話,從客戶端那邊接續接受資料使得data變為8位元組 if len(data) < 8: data += self.conn.recv(8-len(data)) #將data的資料資訊存放為key3變數(前面的第一個八個位元組為key3) #key3 = data[:8] #將data後面的資料作為buffer進行存放 self.buffer = data[8:] #根據key1,key2,key3產生token? #根據客戶的key1、key2、8位元組的關鍵字 #產生一個16位的安全祕鑰 #old-Protocol #token = self.generate_token(key1, key2, key3) #new Protocol token = generate_token_2(self, key) #握手過程,伺服器構建握手的資訊,進行驗證和匹配 #Upgrade: WebSocket 表示為一個特殊的http請求,請求目的為從http協議升級到websocket協議 handshake = '\ HTTP/1.1 101 Web Socket Protocol Handshake\r\n\ Upgrade: WebSocket\r\n\ Connection: Upgrade\r\n\ Sec-WebSocket-Origin: %s\r\n\ Sec-WebSocket-Location: %s\r\n\r\n\ ' %(headers['Origin'], headers['Location']) #服務端傳送握手資料 & 根據Key產生的Token值 self.conn.send(handshake+token) #這個操作之後才設定為握手狀態 self.handshaken = True #Log輸出狀態:套接字x與客戶y握手成功。 print 'Socket%s Handshaken with %s success!' % (self.index,self.remote) #向全部連線客戶端集合傳送訊息,(環境套接字x的到來) sendMessage('Welcome, '+self.name+' !') else: #如果已經握手 #從客戶端讀取64位元組的資料 self.buffer += self.conn.recv(64) #如果資料中存在FF的標誌,則按照此標誌進行分解 if self.buffer.find("\xFF")!=-1: #分解方式啥含義?? s = self.buffer.split("\xFF")[0][1:] #如果訊息是'終止',則列印Socket退出 if s=='quit': print 'Socket%s Logout!' % (self.index) #全體同志Socket退出的狀態(進行GUI更新準備) sendMessage(self.name+' Logout') #同時刪除socket連線集合 deleteconnection(str(self.index)) #同時關閉對應的WebSocket連線(多執行緒關係) self.conn.close() break else: #否則輸出,Socket x收到客戶端的訊息 y print 'Socket%s Got msg:%s from %s!' % (self.index,s,self.remote) #向全體的客戶端輸出連線的資訊 sendMessage(self.name+':'+s) #Buffer資訊再一次的清空 self.buffer = "" def generate_token_2(self, key): key = key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' ser_key = hashlib.sha1(key).digest() return base64.b64encode(ser_key) def generate_token(self, key1, key2, key3): #list/tuple(ls)-list元組相互轉換 #這句話沒看懂,如何理解key是否為數字 num1 = int("".join([digit for digit in list(key1) if digit.isdigit()])) #解析key1中空格的個數 spaces1 = len([char for char in list(key1) if char == " "]) #解析後number2物件 num2 = int("".join([digit for digit in list(key2) if digit.isdigit()])) #統計空格的個數?安全性驗證 spaces2 = len([char for char in list(key2) if char == " "]) #按照一定的格式進行打包,然後進行網路傳輸(格式可以自己進行預訂) #struck.pack:http://blog.sina.com.cn/s/blog_4b5039210100f1tu.html combined = struct.pack(">II", num1/spaces1, num2/spaces2) + key3 #對打包的值進行md5解碼後,並返回二進位制的形式 ##hexdigest() 為十六進位制值,digest()為二進位制值 #處理MD5: http://wuqinzhong.blog.163.com/blog/static/4522231200942225810117/ return hashlib.md5(combined).digest() #建立WebSocket伺服器物件() class WebSocketServer(object): #初始化時,socket為空 def __init__(self): self.socket = None #開啟操作 def begin(self): #伺服器盡心啟動Log輸出 print 'WebSocketServer Start!' #建立TCP的套接字,監聽IP、Port #這裡可以自己進行設定,最多可以收聽50個請求客戶 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ip = 'localhost' port = 8080 #print "WebServer is listening %s,%d" % ip,port #self.socket.bind(ip,port) self.socket.bind((ip,port)) self.socket.listen(50) #宣告全域性連線集合 global connectionlist i=0 while True: #伺服器響應請求,返回連線客戶的資訊(連線fd,客戶地址) connection, address = self.socket.accept() #address資訊中的第1個字串為username物件 username=address[0] #根據連線的客戶資訊,建立WebSocket物件(本質為一個執行緒) #連線後sockfd,連線index,使用者名稱,地址 newSocket = WebSocket(connection,i,username,address) #執行緒啟動 newSocket.start() #更新連線的集合(hash表的對應關係)-name->sockfd connectionlist['connection'+str(i)]=connection i = i + 1 if __name__ == "__main__": server = WebSocketServer() server.begin()
## client.html頁面
<html> <head> <title>WebSocket</title> <style> html,body{font:normal 0.9em arial,helvetica;} #log {width:440px; height:200px; border:1px solid #7F9DB9; overflow:auto;} #msg {width:330px;} </style> <script> var socket; function init(){ var host = "ws://127.0.0.1:8080/"; try{ socket = new WebSocket(host); socket.onopen = function(msg){ ; }; socket.onmessage = function(msg){ log(msg.data); }; socket.onclose = function(msg){ log("Lose Connection!"); }; } catch(ex){ log(ex); } $("msg").focus(); } function send(){ var txt,msg; txt = $("msg"); msg = txt.value; if(!msg){ alert("Message can not be empty"); return; } txt.value=""; txt.focus(); try{ socket.send(msg); } catch(ex){ log(ex); } } window.onbeforeunload=function(){ try{ socket.send('quit'); socket.close(); socket=null; } catch(ex){ log(ex); } }; function $(id){ return document.getElementById(id); } function log(msg){ $("log").innerHTML+="<br>"+msg; } function onkey(event){ if(event.keyCode==13){ send(); } } </script> </head> <body onload="init()"> <h3>WebSocket</h3> <br><br> <div id="log"></div> <input id="msg" type="textbox" onkeypress="onkey(event)"/> <button onclick="send()">傳送</button> </body> </html>
## 用法說明
websocket.py
訪問:http://localhost:8080/client.html
相關推薦
python之WebSocket的開發
## websocket.py import socket import struct import hashlib,base64 import threading,random #執行緒,套接字,雜湊表,隨機數 #存放連結客戶fd,元組 connectionlist =
python之部署開發環境
Python 一、部署開發環境(windows) 1.建立工作區域 Python -Package -Program &nbs
python之美--開發原則篇
上一篇詳細的介紹了python的幾個有深度的知識點,本篇我想再昇華到一個高度,python開發中到底要遵守哪些原則。 1 可讀性: 我把可讀性放在python原則第一位,是因為python太大的靈活性,導致了每個人的程式碼風格天馬行空。像Java那種語言規定的很嚴謹,雖
python之WebSocket協議
一、WebSocket理論部分 1、websocket是什麼 Websocket是html5提出的一個協議規範,參考rfc6455。 websocket約定了一個通訊的規範,通過一個握手的機制,客戶端(瀏覽器)和伺服器(webserver)之間能建立一個類似tcp的連線
Python之路57-前端快速開發
python適用於全棧BootStrapcss、js學習BootStrap規則1.響應式@media<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title&
Python全棧開發之4、內置函數、文件操作和遞歸
開發 hang mon alien yun alpha err fdm ax1 %E5%AD%97%E8%8A%82%E5%BA%8F%E8%BD%AC%E6%8D%A2%E4%B8%8E%E7%BB%93%E6%9E%84%E4%BD%93%E4%BD%8D%E5%9F%
python全棧開發從入門到放棄之函數基礎
*args 才會 沒有 pri 關鍵字 args none 結果 類型 1、為什麽要用函數#1.避免代碼重用#2.提高代碼的可讀性 2、函數的定義def 函數名(參數1,參數2): ‘‘‘函數註釋‘‘‘ print("函數體") return "返回值"
python全棧開發從入門到放棄之裝飾器函數
def return app 不改變 art sdl 兩個 time() 必須 1、函數名可以當作函數的參數 1 import time 2 def timmer(func): 3 #函數名可以當做函數的參數 4 def inner(): 5
python全棧開發從入門到放棄之常用模塊和正則
imp 管理 gin idt 由於 說明 多次 mar style 什麽是模塊? 常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。 但其實import加載的模塊分為四個通用類別: 1 使用python編寫
python全棧開發從入門到放棄之socket網絡編程基礎
windows lis timeout 標準 網站 入門 make 取數 exce 網絡編程基礎 一 客戶端/服務器架構 1.硬件C/S架構(打印機) 2.軟件C/S架構 互聯網中處處是C/S架構 如黃色網站是服務端,你的瀏覽器是客戶端(B/S架構也是C/S架構的一
python全棧開發從入門到放棄之socket並發編程之IO模型
map 超時 sting mon recv style 好的 exceptio 得到 一 IO模型介紹 同步(synchronous) IO和異步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分別是什麽,到底有什
python全棧開發之Python基礎(1)
python 基礎一、 基礎知識 python的運行方式有兩種: 第一種通過交互式的運行方式,通過 "開始"—>"所有程序" —> "python3.x" —>"IDLE" 運行。 第二種是我們寫好的Pyth
python之路--day15---軟件開發目錄規範
python 配置 文件 inf 功能 介紹 b- info bubuko 軟件開發目錄規範 bin--啟動文件 conf--配置文件 core--核心代碼 db--數據文件 lib--常用功能代碼 log--日誌文件 readme--軟件介紹 python之路--da
Python 之 網絡編程——SOCKET開發
top mage pan .so byte exc dto xxd 2.4.1 一、預備知識 對於我們,主要掌握5層協議就行。 物理層: 轉成二進制數序列數據鏈路層: 形成統一的協議:Internet協議 包括數據頭(18個字節,前6個字節原地址,中間6個字節為目
《Python運維開發之路》 內置函數&數據結構(六)
ima oob 更新 .com 常用 嵌套列表 數據結構 例子 func 一、Python內置函數詳解 Python內置函數圖解 您也可以訪問(裏面有各種例子):https://docs.python.org/3/library/functions.html#nex
python全棧開發之路
方法 blog 數據 數據類型 框架 blank 全棧 jquery基礎 one 一、Python基礎 python簡介 python數據類型(數字\字符串\列表) python數據類型(元組\字典) 二、Python文件操作&函數 三、Pytho
Python全棧開發之路 【第八篇】:面向對象編程設計與開發(2)
ssi pen 解析 執行 示例 動態 類型 put 所有 一、繼承與派生 什麽是繼承? 繼承指的是類與類之間的關系,是一種什麽是什麽的關系,繼承的功能之一就是用來解決代碼重用問題。 繼承是一種創建新的類的方式,在python中,新建的類可以繼承一個或多個父類,父類又可以成
Python全棧開發之路 【第十八篇】:Ajax技術
加載 完全 三種 請求 技術 當前頁 n) let 保存 Ajax技術 Ajax = 異步 JavaScript 和 XML。 Ajax 是一種在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術。 1、jQuery的load()方法 jQuery load()方法是簡單
python之模塊、包的導入過程和開發規範
而是 port code 導入模塊 聲明 for 命名 bubuko 根據 摘要:導入模塊、導入包、編程規範 以My_module為例,My_module的代碼如下: __all__ = [‘name‘,‘read‘] print(‘in mymod
Python全棧開發之基礎語法
deepcopy 分配 有符號 數字 桌面應用 存儲 tex 算術運算符 多行 No1. Python語言介紹 詳情見百度百科。。。 No.2 Python是一門怎麽樣的語言 詳情在百度百科。。。 No3. Python能做什麽 網絡應用、桌面應用、系統運維、機器學習、科學