一個用python寫的websocket服務端
由於要在頁面上呼叫後臺的一個shell程式,但是這個shell執行時間很長,如果非同步獲取shell的輸出?而不必漫長的等待shell執行完畢才會一下把資料全部輸出?
我們知道原生的http協議不可能完成這個要求,除非你把輸出更新到一個文本里,然後用js倫詢去取,這不扯淡嗎
因為是內部的程式,當然有這樣要求的程式基本都是內部,或者小團體使用,所以,嘗試一下websocket吧
先研究一下websocket協議
首先是握手 handleshake
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
然後伺服器會返回這麼一個頭給客戶端
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat
其中有一個注意點
Sec-WebSocket-Key和
Sec-WebSocket-Accept前者是客戶端,也就是客戶端生成的,那麼後者咋生成咧
公式如下
Sec-WebSocket-Accept = base64(sha1(Sec-WebSocket-Key+258EAFA5-E914-47DA-95CA-C5AB0DC85B11))
"+"號不算在內
具體python程式碼如下
# -*- coding: utf8 -*- import socket import time from threading import Thread import hashlib import base64 class returnCrossDomain(Thread): def __init__(self,connection): Thread.__init__(self) self.con = connection self.isHandleShake = False def run(self): while True: if not self.isHandleShake: #握手 clientData = self.con.recv(1024) dataList = clientData.split("\r\n") header = {} print clientData for data in dataList: if ": " in data: unit = data.split(": ") header[unit[0]] = unit[1] secKey = header['Sec-WebSocket-Key']; resKey = base64.encodestring(hashlib.new("sha1",secKey+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest()).replace('\n',''); response = '''HTTP/1.1 101 Switching Protocols\r\n''' response += '''Upgrade: websocket\r\n''' response += '''Connection: Upgrade\r\n''' response += '''Sec-WebSocket-Accept: %s\r\n'''%(resKey,) response += '''Sec-WebSocket-Protocol: chat\r\n\r\n''' self.con.send(response) self.isHandleShake = True else: data = self.con.recv(1024) print data def main(): sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind(('',88)) sock.listen(100) while True: try: connection,address = sock.accept() returnCrossDomain(connection).start() except: time.sleep(1) if __name__=="__main__": main()
注意注意,python的base64.encodestring 會自動加一個\n需要給處理掉
js程式碼如下
var socket = new WebSocket('ws://localhost:88');
socket.onopen = function() {
alert(1);
}
順利彈出1
下邊開始研究資料傳輸 有一個問題折騰了我好久,就是因為我複製的時候沒有把這個頭給去掉,導致瀏覽器一直收不到資訊,我鬱悶阿
response += '''Sec-WebSocket-Protocol: chat\r\n\r\n'''
這句話的意思就是,使用chat這個協議,而不使用websocket協議,所以我按照websocket協議來,肯定怎麼都收不到資料,去掉之後,果斷成功
websocket的資料傳輸部分有點小麻煩,老版本的websocket 是很簡單的,每條訊息都是 一個0xFF打頭,0x00結尾,很容易,但是肯定會引發安全問題
新版本的協議如下
服務端從客戶端讀資料
1.讀1Byte位元組,注意是Byte=8bits,這個要注意,奶奶的,剛看說明文件的時候,看過了,怎麼也看不懂
這1個Byte分 8個bit ,前4個bit 不去研究,後4個bit代表這個資料段的作用,比如是一條資料,一條socket關閉資訊等,
獲取這四個位元組很簡單
data_head = self.con.recv(1)
header = struct.unpack("B",data_head)[0]
opcode = header & 0b00001111
具體的opcode定義如下
* %x0 denotes a continuation frame * %x1 denotes a text frame * %x2 denotes a binary frame * %x3-7 are reserved for further non-control frames * %x8 denotes a connection close * %x9 denotes a ping * %xA denotes a pong * %xB-F are reserved for further control frames
2.再讀取1個byte注意是byte=8個bits
這8個bits分兩端,第一bit代表是否masking,我的理解就是是否加密
後7個bits代表著真正資料的長度payloadlength,如果payloadlength<=125那麼資料長度就是payloadlength,如果payloadlength=126,那麼就再去2Bytes的unsiged integer,來代表資料長度,如果payloadlength = 127 那麼 就再讀8個位元組的unsignedlonglong,具體程式碼如下
data_length = self.con.recv(1)
data_lengths= struct.unpack("B",data_length)
data_length = data_lengths[0]& 0b01111111
print bin(data_lengths[0])
masking = data_lengths[0] >> 7
if data_length<=125:
payloadLength = data_length
elif data_length==126:
payloadLength = struct.unpack("H",self.con.recv(2))[0]
elif data_length==127:
payloadLength = struct.unpack("Q",self.con.recv(8))[0]
print "字串長度是:%d"%(data_length,)
3.上一步 讀取到的masking 用來判斷是否加密
如果masking==1
那麼就讀取4個Bytes
然後按照長度讀取資料,進行解密工作,具體程式碼和演算法如下
如果masking==0
那麼就直接讀取剛才計算得到的資料長度的資料了
if masking==1:
print "是masking"
maskingKey = self.con.recv(4)
self.maskingKey = maskingKey
data = self.con.recv(payloadLength)
i = 0
true_data = ''
for d in data:
true_data += chr(ord(d) ^ ord(maskingKey[i%4]))
i += 1
self.onData(true_data)
ok讀取客戶端的資料完成,下邊是傳送資料
傳送資料很簡單,和接收資料一樣的格式,不過我們就不用masking 加密了,所以第二個位元組的第一個bit設為0
具體程式碼如下
def sendData(self,text) :
print "給客戶端傳送資訊%s"%(text,)
#頭
self.con.send(struct.pack("!B",0x81))
#計算長度
length = len(text)
# masking = 0b00000000;
if length<=125:
self.con.send(struct.pack("!B",length))
elif length<=65536:
self.con.send(struct.pack("!B",126))
self.con.send(struct.pack("!H",length))
else:
self.con.send(struct.pack("!B",127))
self.con.send(struct.pack("!Q",length))
self.con.send(struct.pack("!%ds"%(length,),text))
具體的程式碼可以去我的git上下載,我已經封裝好了模組,對應的js也有一個寫好的類,裡邊有demo 歡迎大家嘗試
相關推薦
一個用python寫的websocket服務端
由於要在頁面上呼叫後臺的一個shell程式,但是這個shell執行時間很長,如果非同步獲取shell的輸出?而不必漫長的等待shell執行完畢才會一下把資料全部輸出? 我們知道原生的http協議不可能完成這個要求,除非你把輸出更新到一個文本里,然後用js倫詢去取,這不扯淡嗎
用java寫websocket客戶端
最近用websocket寫一個通訊的系統,伺服器用tocmat,客戶端使用android,為了在android端用java進行websocket通訊在網上找個很久的資料,搜客戶端出來的很多都是js實現的客戶端,最合適的就是一個叫java-websocket的開源
用qt寫tcp服務端和客戶端介面遇到的問題及解決方法
問題1 #include <QTcpSocket> #include <QtcpServer> 在包含這兩個標頭檔案時提示找不到檔案 此時需要在此工程的.pro檔案中新增 QT += network 問題2 服務端的ui介
一個用python寫的用命令列看糗百的小工具
#!/usr/bin/python #coding:utf-8 #作者:Byron #部落格:http://jiabin.tk import urllib2 import re #定義程式主函式 def qiubai(page): url = "http://w
用python寫一個小型的FTP客戶端軟體
第一次用Python語言寫的程式,功能可以基本實現,還有很多不足的地方,需要改進。#!/usr/local/env python #-*- coding:UTF-8 -*- import ftplib import os import socket #HOST='192
用python 寫的一個oracle 服務響應時間的實時監控web 小工具
主要工具: python,flask,SQLLITE (我沒有選擇mysql,sqllite 夠用了,本來就是一個小功能,我喜歡簡單) 主要功能: 監控oracle 10g,11g 資料庫平均響應時間,通過實施採集資料庫rt 並生成趨勢圖,方便客戶通過大屏簡單明瞭,
用Python寫一個批量生成賬號的函數(用戶控制數據長度、數據條數)
shuf open 小寫 長度 數據 ase 函數 用戶控制 app # 1、寫一個函數,批量生成一些註冊使用的賬號:[email protected]/* */,長度由用戶輸入,產生多少條也由用戶輸入,用戶名不能重復,用戶名必須由大寫字母、小寫字母、數字組成
用Python寫一個小遊戲
python 小腳本 剛學Python時間不長,但也知道了一點,看別人的參考寫了一個猜數字小遊戲,也算是禹學於樂吧。#!/usr/bin/env python #coding=utf-8
用python寫一個簡單的excel表格獲取當時的linux系統信息
psutil 生成 之前 建立 set ces ext 流量 關閉 最近在學習excel表格的制作,順便結合之前學習的內容,利用python的兩個模板,分別是獲取系統信息的psutil,和生成excel表格的xlsxwriter。利用這兩個模板將生成一個簡單的excel表格
用python寫一個九九乘法表-2月19日/2018
九九乘法 while -c pos ont 九九 pytho 九九乘法表 font first = 1 while first<=9: sec=1 while sec<=first: print(str(sec),"x",str(first),
用python寫一個restful API
python restful # -*- coding: utf-8 -*- # 作者: 煮酒品茶 """ package.module ~~~~~~~~~~~~~~ python實現的圖書的一個restful api. 參考restful設計指南 URL:
用python寫一個微信聊天機器人
python wechat 聊天機器人 # -*- coding: utf-8 -*- """ package.module ~~~~~~~~~~~~~~ 一個微信機器人程序 微信客戶端itchat: http://itchat.readthed
用python寫一個微信跳一跳外掛,瞬間稱霸朋友圈
python 微信 跳一跳 爬蟲12月28日,微信宣布,小程序增加了新的類目:小遊戲,同時上線小遊戲 你們跳的再好,在毫無心理波動的程序面前都是渣渣。 剛剛會python的小白想玩怎麽辦? 下有詳細的教程,哈哈,包教會不收任何的費用。 感受一下被支配的恐懼吧: 使用工具1.python3.6 2.adb 3
給女朋友用Python寫了一個自動抽獎程序!Python在手,獎品我有!
com () 單身 代碼 女孩子 nbsp 不能 是不是 apt 我相信大部分的女孩子都是喜歡買買買的,我還沒有見過不喜歡買東西的女孩子,當然很多東西也是有抽獎這項優惠的,很多小程序都有抽獎這個功能的,好了廢話不多說了,為了給女朋友寫這款抽獎程序,可謂是嘔心瀝血!不過看到她
asp微信小程序獲取用戶頭像和微信名-asp寫的服務端
詳細信息 openid total ont login urlencode hat console storage //index.js//獲取應用實例var app = getApp()Page({ data: { paydata: { title: "支付測試"
用python寫的一個簡易的雲音樂播放器
本人最近在學習python,在看了一些教程後,用python寫了一個簡單的雲音樂播放器,下面把主要程式碼貼上來,其中用到了github上他人寫的一個漢字轉拼音的庫,大家可以在github上找到。 #coding=utf-8 from Tkinter import * import tkMess
用Python 寫一個TCP 伺服器和TCP代理
TCP伺服器 import socket import threading bind_ip="0.0.0.0" bind_port=9999 server=socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind((bind_i
用Python寫一個語音播放軟體
單位經常使用廣播進行臨時事項的通知(將文字轉換為語音然後通過功放廣播),但是市面上多數語音播放軟體都是收費的,要麼發音失真,要麼不夠穩定——經常出現莫名其妙的故障,容易給工作帶來被動。學Python這麼久不如動手寫一款自己的語音廣播軟體,即使發生故障也可以自行排除。 介面設計 在開始動
用python寫一個抽獎程式
第一次使用python寫程式,確實比C/C++之類方便許多。既然這個抽獎的資料不大,對效率要求並不高,所以採用python寫,更加簡潔、清晰、方便。 1.用到的模組 生成隨機數的模組random 用來讀取excel表格的模組xlrd 2.思路:首先開啟e
我用Python寫了一個共享單車的應用程式!下一個摩拜單車會是我嗎
學習如何使用 Redis 和 Python 構建一個位置感知的應用程式。 我經常出差。但不是一個汽車狂熱分子,所以當我有空閒時,我更喜歡在城市中散步或者騎單車。我參觀過的許多城市都有共享單車系統,你可以租個單車用幾個小時。大多數系統都有一個應用程式來幫助使用者定位和租用他們的單車,但對於像我這樣