后端 server源碼
#-*- coding:utf8 -*-
import threading
import hashlib
import socket
import base64
global clients
clients = {}
#通知客戶端
def notify(message):
? ? for connection in clients.values():
? ? ? ? connection.send('%c%c%s' % (0x81, len(message), message))
#客戶端處理線程
class websocket_thread(threading.Thread):
? ? def __init__(self, connection, username):
? ? ? ? super(websocket_thread, self).__init__()
? ? ? ? self.connection = connection
? ? ? ? self.username = username
? ? def run(self):
? ? ? ? print 'new websocket client joined!'
? ? ? ? data = self.connection.recv(1024)
? ? ? ? headers = self.parse_headers(data)
? ? ? ? token = self.generate_token(headers['Sec-WebSocket-Key'])
? ? ? ? self.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)
? ? ? ? while True:
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? data = self.connection.recv(1024)
? ? ? ? ? ? except socket.error, e:
? ? ? ? ? ? ? ? print "unexpected error: ", e
? ? ? ? ? ? ? ? clients.pop(self.username)
? ? ? ? ? ? ? ? break
? ? ? ? ? ? data = self.parse_data(data)
? ? ? ? ? ? if len(data) == 0:
? ? ? ? ? ? ? ? continue
? ? ? ? ? ? message = self.username + ": " + data
? ? ? ? ? ? notify(message)
? ? def parse_data(self, 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(self, 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(self, msg):
? ? ? ? key = msg + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
? ? ? ? ser_key = hashlib.sha1(key).digest()
? ? ? ? return base64.b64encode(ser_key)
#服務端
class websocket_server(threading.Thread):
? ? def __init__(self, port):
? ? ? ? super(websocket_server, self).__init__()
? ? ? ? self.port = port
? ? def run(self):
? ? ? ? sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
? ? ? ? sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
? ? ? ? sock.bind(('127.0.0.1', self.port))
? ? ? ? sock.listen(5)
? ? ? ? print 'websocket server started!'
? ? ? ? while True:
? ? ? ? ? ? connection, address = sock.accept()
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? username = "ID" + str(address[1])
? ? ? ? ? ? ? ? thread = websocket_thread(connection, username)
? ? ? ? ? ? ? ? thread.start()
? ? ? ? ? ? ? ? clients[username] = connection
? ? ? ? ? ? except socket.timeout:
? ? ? ? ? ? ? ? print 'websocket connection timeout!'
if __name__ == '__main__':
? ? server = websocket_server(9000)
? ? server.start()
前端html源碼
<!--
@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="發(fā)送文本" value="I'm WebSocket Client!" />
? ? ? ? ? ? ? ? <input id="btnSend" type="button" value="發(fā)送" 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://www.cnblogs.com/lichmama/p/3931212.html