1. 程式人生 > >一個用python寫的websocket服務端

一個用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 歡迎大家嘗試

相關推薦

一個pythonwebsocket服務

由於要在頁面上呼叫後臺的一個shell程式,但是這個shell執行時間很長,如果非同步獲取shell的輸出?而不必漫長的等待shell執行完畢才會一下把資料全部輸出? 我們知道原生的http協議不可能完成這個要求,除非你把輸出更新到一個文本里,然後用js倫詢去取,這不扯淡嗎

javawebsocket客戶

最近用websocket寫一個通訊的系統,伺服器用tocmat,客戶端使用android,為了在android端用java進行websocket通訊在網上找個很久的資料,搜客戶端出來的很多都是js實現的客戶端,最合適的就是一個叫java-websocket的開源

qttcp服務和客戶介面遇到的問題及解決方法

問題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 構建一個位置感知的應用程式。 我經常出差。但不是一個汽車狂熱分子,所以當我有空閒時,我更喜歡在城市中散步或者騎單車。我參觀過的許多城市都有共享單車系統,你可以租個單車用幾個小時。大多數系統都有一個應用程式來幫助使用者定位和租用他們的單車,但對於像我這樣