首页 > 代码库 > 对不支持原生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(/&/, "&amp;").replace(/</, "&lt;")33                 .replace(/>/, "&gt;").replace(/"/, "&quot;"); // "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 socket25     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 websocket15         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 close20         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的浏览器进行兼容