天天看點

js 與 python 之間的websocekt互動

# -*- coding:utf8 -*-

import threading
import hashlib
import socket
import base64


class websocket_thread(threading.Thread):
    def __init__(self, connection):
        super(websocket_thread, self).__init__()
        self.connection = connection

    def run(self):
        print 'new websocket client joined!'
        reply = 'i got u, from websocket server.'
        length = len(reply)
        while True:
            data = self.connection.recv(1024)
            print parse_data(data)
            self.connection.send('%c%c%s' % (0x81, length, reply))


def parse_data(msg):
    v = ord(msg[1]) & 0x7f
    if v == 0x7e:
        p = 4
    elif v == 0x7f:
        p = 10
    else:
        p = 2
    mask = msg[p:p + 4]
    data = msg[p + 4:]

    return ''.join([chr(ord(v) ^ ord(mask[k % 4])) for k, v in enumerate(data)])


def parse_headers(msg):
    headers = {}
    header, data = msg.split('\r\n\r\n', 1)
    for line in header.split('\r\n')[1:]:
        key, value = line.split(': ', 1)
        headers[key] = value
    headers['data'] = data
    return headers


def generate_token(msg):
    key = msg + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
    ser_key = hashlib.sha1(key).digest()
    return base64.b64encode(ser_key)


if __name__ == '__main__':
    #socket(family,type[,protocal]) 使用給定的位址族、套接字類型、協定編号(預設為0)來建立套接字。
    '''
    socket.AF_UNIX  隻能夠用于單一的Unix系統程序間通信
    socket.AF_INET  伺服器之間網絡通信
    socket.AF_INET6 IPv6
    socket.SOCK_STREAM  流式socket , for TCP
    socket.SOCK_DGRAM   資料報式socket , for UDP
    建立TCP Socket:s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    建立UDP Socket:s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    '''

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #s.setsockopt(level,optname,value) 設定給定套接字選項的值。
    #打開或關閉位址複用功能。當option_value不等于0時,打開,否則,關閉。它實際所做的工作是置sock->sk->sk_reuse為1或0。
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1', 9000))
    sock.listen(5)
    #首先,我們建立了一個套接字,然後讓套接字開始監聽接口,并且最多隻能監聽5個請求
    while True:
        connection, address = sock.accept()
           
#接受監聽到的連接配接請求,
        print address
        try:
            data = connection.recv(1024)
            headers = parse_headers(data)
            token = generate_token(headers['Sec-WebSocket-Key'])
            connection.send('\
HTTP/1.1 101 WebSocket Protocol Hybi-10\r\n\
Upgrade: WebSocket\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-Accept: %s\r\n\r\n' % (token))
            thread = websocket_thread(connection)
            thread.start()
        except socket.timeout:
            print 'websocket connection timeout'
           
<!--
@http://www.cnblogs.com/zhuweisky/p/3930780.html
-->
<!DOCTYPE html>
</html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h3>WebSocketTest</h3>
        <div id="login">
            <div>
                <input id="serverIP" type="text" placeholder="伺服器IP" value="127.0.0.1" autofocus="autofocus" />
                <input id="serverPort" type="text" placeholder="伺服器端口" value="9000" />
                <input id="btnConnect" type="button" value="連接配接" onclick="connect()" />
            </div>
            <div>
                <input id="sendText" type="text" placeholder="發送文本" value="I'm WebSocket Client!" />
                <input id="btnSend" type="button" value="發送" onclick="send()" />
            </div>
            <div>
                <div>
                    來自服務端的消息
                </div>
                <textarea id="txtContent" cols="50" rows="10" readonly="readonly"></textarea>
            </div>
        </div>
    </body>
    <script>
        var socket;

        function connect() {
            var host = "ws://" + $("serverIP").value + ":" + $("serverPort").value + "/"
            socket = new WebSocket(host);
            try {

                socket.onopen = function (msg) {
                    $("btnConnect").disabled = true;
                    alert("連接配接成功!");
                };

                socket.onmessage = function (msg) {
                    if (typeof msg.data == "string") {
                        displayContent(msg.data);
                    }
                    else {
                        alert("非文本消息");
                    }
                };

                socket.onclose = function (msg) { alert("socket closed!") };
            }
            catch (ex) {
                log(ex);
            }
        }

        function send() {
            var msg = $("sendText").value
            socket.send(msg);
        }

        window.onbeforeunload = function () {
            try {
                socket.close();
                socket = null;
            }
            catch (ex) {
            }
        };

        function $(id) { return document.getElementById(id); }

        Date.prototype.Format = function (fmt) { //author: meizz
            var o = {
                "M+": this.getMonth() + 1, //月份
                "d+": this.getDate(), //日
                "h+": this.getHours(), //小時
                "m+": this.getMinutes(), //分
                "s+": this.getSeconds(), //秒
                "q+": Math.floor((this.getMonth() + 3) / 3), //季度
                "S": this.getMilliseconds() //毫秒
            };
            if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
            for (var k in o)
                if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            return fmt;
        }

        function displayContent(msg) {
            $("txtContent").value += "\r\n" +new Date().Format("yyyy/MM/dd hh:mm:ss")+ ":  " + msg;
        }
        function onkey(event) { if (event.keyCode == 13) { send(); } }
    </script>
</html>


原創位址:https://blog.csdn.net/prayallforyou/article/details/53737295