python 模拟websocket通信

本文介绍如何使用 Python 实现 WebSocket 通信。包括服务端与客户端的搭建过程,通过示例代码展示了如何建立连接并进行双向数据交换。同时提供了一个简单的 HTML 客户端页面和 Python 模拟客户端。

python 模拟websocket通信

以前,很多网站使用轮询实现推送技术。轮询是在特定的的时间间隔(比如1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给浏览器。轮询的缺点很明显,浏览器需要不断的向服务器发出请求,然而HTTP请求的header是非常长 的,而实际传输的数据可能很小,这就造成了带宽和服务器资源的浪费。

Comet使用了AJAX改进了轮询,可以实现双向通信。但是Comet依然需要发出请求,而且在Comet中,普遍采用了长链接,这也会大量消耗服务器带宽和资源。

于是,WebSocket协议应运而生。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器通过 TCP 连接直接交换数据。WebSocket 连接本质上是一个 TCP 连接。

WebSocket在数据传输的稳定性和数据传输量的大小方面,具有很大的性能优势。

1.websocket服务端

#!/usr/bin/env python
# -*- coding: utf-8 -*-

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)
            re = parse_data(data)
            print re
            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__':
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1', 9002))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        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'

2.客户端

<!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="9002" />
                <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>

3.python模拟客户端

首先需要安装websocket-client,安装命令如下:
pip install websocket-client

#! /usr/bin/env python
# -*- coding:utf-8 -*-


import time
from websocket import create_connection
ws = create_connection("ws://127.0.0.1:9002/")
print "Sending 'Hello, World'..."
for i in range(10, 20):
    time.sleep(1000)
    ws.send("Hello, World %s" % i)
    print "Sent %s",  i
    print "Reeiving...%s",  i
    result = ws.recv()
    print "Received '%s'" % result
time.sleep(30)
ws.close()

4.启动websocket服务,启动客户端,启动模拟客户端

启动websocket服务: python websocket.py

启动客户端: 浏览器打开此html文件

启动模拟客户端: python client.py【可以改变一下数值,多开几个模拟客户端试试】

参考文档:http://www.cnblogs.com/UnGeek/p/5335462.html

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值