首页 > 代码库 > 对不支持原生html5 websocket的浏览器进行兼容
对不支持原生html5 websocket的浏览器进行兼容
结果:
转载请注明:TheViper
从github上的 web-socket-js (socket.io好像也是用这个做的他们的flash替代传输方式)改过来的。不过值得注意的是里面的flash websocket代理文件,文件实在是很大,有174k
很好奇,就反编译看下,
是flex做的,这点很不喜欢,因为我没有flex builder也不想因为去改代码重新装一个,然后mx包下面的是flex的组件,com包下是adobe封装的socket和两个加密包 .
最下面那个包才是最主要的,代码不是很复杂,就是利用actionscript3的socket,与那边服务端socket握手,传递消息,不过区别是,在connect的时候要把header封装成websocket的样子
这也是flash模拟websocket的原理。
我花了点时间把源码里面和加密有关的代码都注释掉,加密的代码都是和wss(类似于https)有关的,用flash编译了一下,主要就是把mx包加到flash编译里面,flex是臃肿版的flash,结果大小只有20k!原来加密让文件大太多了!
websocket.js
1 define("websocket", function() { 2 (function() { 3 if (window.WEB_SOCKET_FORCE_FLASH) { 4 // Keeps going. 5 } 6 else if (window.WebSocket) { 7 return; 8 } else if (window.MozWebSocket) { 9 // Firefox. 10 window.WebSocket = MozWebSocket; 11 return; 12 } 13 var logger; 14 if (window.WEB_SOCKET_LOGGER) { 15 logger = WEB_SOCKET_LOGGER; 16 } else if (window.console && window.console.log && window.console.error) { 17 logger = window.console; 18 } else { 19 logger = {log: function(){ }, error: function(){ }}; 20 } 21 window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) { 22 var self = this; 23 self.__id = WebSocket.__nextId++; 24 WebSocket.__instances[self.__id] = self; 25 self.readyState = WebSocket.CONNECTING; 26 self.bufferedAmount = 0; 27 self.__events = {}; 28 if (!protocols) { 29 protocols = []; 30 } else if (typeof protocols == "string") { 31 protocols = [protocols]; 32 } 33 self.__createTask = setTimeout(function() { 34 WebSocket.__addTask(function() { 35 self.__createTask = null; 36 WebSocket.__flash.create( 37 self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null); 38 }); 39 }, 0); 40 }; 41 WebSocket.prototype.send = function(data) { 42 if (this.readyState == WebSocket.CONNECTING) { 43 throw "INVALID_STATE_ERR: Web Socket connection has not been established"; 44 } 45 var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data)); 46 if (result < 0) { // success 47 return true; 48 } else { 49 this.bufferedAmount += result; 50 return false; 51 } 52 }; 53 WebSocket.prototype.close = function() { 54 if (this.__createTask) { 55 clearTimeout(this.__createTask); 56 this.__createTask = null; 57 this.readyState = WebSocket.CLOSED; 58 return; 59 } 60 if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) { 61 return; 62 } 63 this.readyState = WebSocket.CLOSING; 64 WebSocket.__flash.close(this.__id); 65 }; 66 WebSocket.prototype.dispatchEvent = function(event) { 67 var events = this.__events[event.type] || []; 68 for (var i = 0; i < events.length; ++i) { 69 events[i](event); 70 } 71 var handler = this["on" + event.type]; 72 if (handler) handler.apply(this, [event]); 73 }; 74 WebSocket.prototype.__handleEvent = function(flashEvent) { 75 if ("readyState" in flashEvent) { 76 this.readyState = flashEvent.readyState; 77 } 78 if ("protocol" in flashEvent) { 79 this.protocol = flashEvent.protocol; 80 } 81 var jsEvent; 82 if (flashEvent.type == "open" || flashEvent.type == "error") { 83 jsEvent = this.__createSimpleEvent(flashEvent.type); 84 } else if (flashEvent.type == "close") { 85 jsEvent = this.__createSimpleEvent("close"); 86 jsEvent.wasClean = flashEvent.wasClean ? true : false; 87 jsEvent.code = flashEvent.code; 88 jsEvent.reason = flashEvent.reason; 89 } else if (flashEvent.type == "message") { 90 var data =http://www.mamicode.com/ decodeURIComponent(flashEvent.message); 91 jsEvent = this.__createMessageEvent("message", data); 92 } else { 93 throw "unknown event type: " + flashEvent.type; 94 } 95 this.dispatchEvent(jsEvent); 96 }; 97 WebSocket.prototype.__createSimpleEvent = function(type) { 98 if (document.createEvent && window.Event) { 99 var event = document.createEvent("Event");100 event.initEvent(type, false, false);101 return event;102 } else {103 return {type: type, bubbles: false, cancelable: false};104 }105 };106 WebSocket.prototype.__createMessageEvent = function(type, data) {107 if (window.MessageEvent && typeof(MessageEvent) == "function" && !window.opera) {108 return new MessageEvent("message", {109 "view": window,110 "bubbles": false,111 "cancelable": false,112 "data": data113 });114 } else if (document.createEvent && window.MessageEvent && !window.opera) {115 var event = document.createEvent("MessageEvent");116 event.initMessageEvent("message", false, false, data, null, null, window, null);117 return event;118 } else {119 return {type: type, data: data, bubbles: false, cancelable: false};120 }121 };122 WebSocket.CONNECTING = 0;123 WebSocket.OPEN = 1;124 WebSocket.CLOSING = 2;125 WebSocket.CLOSED = 3;126 WebSocket.__isFlashImplementation = true;127 WebSocket.__initialized = false;128 WebSocket.__flash = null;129 WebSocket.__instances = {};130 WebSocket.__tasks = [];131 WebSocket.__nextId = 0;132 WebSocket.loadFlashPolicyFile = function(url){133 WebSocket.__addTask(function() {134 WebSocket.__flash.loadManualPolicyFile(url);135 });136 };137 WebSocket.__initialize = function() {138 if (WebSocket.__initialized) return;139 WebSocket.__initialized = true;140 if (WebSocket.__swfLocation) {141 window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;142 }143 };144 WebSocket.__onFlashInitialized = function() {145 setTimeout(function() {146 WebSocket.__flash =main.get_flash_obj("webSocketFlash");147 WebSocket.__flash.setCallerUrl(location.href);148 WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);149 for (var i = 0; i < WebSocket.__tasks.length; ++i) {150 WebSocket.__tasks[i]();151 }152 WebSocket.__tasks = [];153 }, 0);154 };155 WebSocket.__onFlashEvent = function() {156 setTimeout(function() {157 try {158 var events = WebSocket.__flash.receiveEvents();159 for (var i = 0; i < events.length; ++i) {160 WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);161 }162 } catch (e) {163 logger.error(e);164 }165 }, 0);166 return true;167 };168 WebSocket.__log = function(message) {169 logger.log(decodeURIComponent(message));170 };171 WebSocket.__error = function(message) {172 logger.error(decodeURIComponent(message));173 };174 WebSocket.__addTask = function(task) {175 if (WebSocket.__flash) {176 task();177 } else {178 WebSocket.__tasks.push(task);179 }180 };181 })();182 return WebSocket;183 });
websocket_main.js
1 require([‘html5/websocket‘,‘avalon-min‘],function(WebSocket,avalon){ 2 var $=function(id){ 3 return document.getElementById(id); 4 }; 5 WEB_SOCKET_DEBUG = true; 6 var ws; 7 ws = new WebSocket("ws://localhost:8888/new-msg/socket"); 8 ws.onopen = function() { 9 output("onopen");10 };11 ws.onmessage = function(e) {12 output("onmessage: " + e.data);13 };14 ws.onclose = function() {15 output("onclose");16 };17 ws.onerror = function() {18 output("onerror");19 };20 avalon.bind($(‘send‘),‘click‘,function(){21 var input = $("input1");22 ws.send(input.value);23 output("send: " + input.value);24 input.valuehttp://www.mamicode.com/= "";25 input.focus();26 });27 avalon.bind($(‘close‘),‘click‘,function(){28 ws.close();29 });30 function output(str) {31 var log = document.getElementById("log");32 var escaped = str.replace(/&/, "&").replace(/</, "<")33 .replace(/>/, ">").replace(/"/, """); // "34 log.innerHTML = escaped + "<br>" + log.innerHTML;35 }36 });
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 5 <title>Insert title here</title> 6 <script src="http://localhost/twitter/js/libs/seed-min.js"></script> 7 <script type="text/javascript" 8 src="http://localhost/twitter/js/libs/flash_embed.js"></script> 9 <script src="http://localhost/twitter/js/main.js" type="text/javascript"></script>10 </head>11 <body>12 <input type="text" id="input1">13 <input type="submit" value="Send" id=‘send‘>14 <button id=‘close‘>close</button>15 <div id="log"></div>16 <div id=‘a‘ style=‘width: 1px; height: 1px;‘></div>17 <script type="text/javascript">18 flash_object.embedSWF(‘http://localhost:8888/swf/WebSocketMain.swf‘,19 ‘a‘, ‘webSocketFlash‘, ‘100%‘, ‘100%‘);20 </script>21 <script type="text/javascript"22 src=‘http://localhost/twitter/js/libs/html5/websocket_main.js‘></script>23 </body>24 </html>
下面很重要,在运行前一定要开启服务端(python)的socket
1 import socket 2 import time 3 from threading import Thread 4 5 class returnCrossDomain(Thread): 6 def __init__(self,connection): 7 Thread.__init__(self) 8 self.con = connection 9 def run(self):10 clientData = http://www.mamicode.com/self.con.recv(1024)11 xmlData = http://www.mamicode.com/‘‘‘<?xml version="1.0" encoding="utf-8"?>‘‘‘12 xmlData += ‘‘‘<cross-domain-policy><policy-file-request/>‘‘‘13 xmlData += ‘‘‘<allow-access-from domain="*" to-ports="*" />‘‘‘14 xmlData += ‘‘‘</cross-domain-policy>\0‘‘‘15 try:16 self.con.send(xmlData)17 except Excepiton,e:18 pass19 self.con.close()20 def main():21 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)22 sock.bind((‘localhost‘,843))23 sock.listen(10000000)24 print ‘socket‘25 while True:26 try:27 connection,address = sock.accept()28 returnCrossDomain(connection).start()29 except:30 time.sleep(1)31 32 if __name__=="__main__":33 main()
服务端用python的tornado写的,也一样在运行前开启tornado
1 # -*- coding: utf-8 -*- 2 import base 3 import tornado.websocket 4 5 def send_message(message): 6 for handler in ChatSocketHandler.socket_handlers: 7 handler.write_message(message) 8 9 class ChatSocketHandler(tornado.websocket.WebSocketHandler):10 socket_handlers = set()11 12 def open(self):13 ChatSocketHandler.socket_handlers.add(self)14 print ‘websocket‘15 send_message(‘A new user has entered the chat room.‘)16 17 def on_close(self):18 ChatSocketHandler.socket_handlers.remove(self)19 print ‘websocket close‘20 send_message(‘A user has left the chat room.‘)21 22 def on_message(self, message):23 print ‘message:‘+message24 send_message(message)
tornado很好的封装了websocket,用起来很简单,加上flash模拟websocket兼容不支持websocket的浏览器,这样可以完美的利用高效的websocket
WebSocketMain.swf文件及源码:http://files.cnblogs.com/TheViper/flash_websocket.zip
对不支持原生html5 websocket的浏览器进行兼容