zoukankan      html  css  js  c++  java
  • 让web socket"兼容"各个浏览器

    建立了Socket服务端,服务器数据有变动,想要推送给客户端,如果是C/S模式,使用Socket自然没问题;如果是B/S呢,没有Socket怎么办?

    html5支持WebSocket,这是一个不错的改善。

    想起没有顺丰、韵达、各种通等之类快递的日子,你以为远方的朋友会给你邮寄包裹——虽然不会有人这样做——然后你就翻山越岭天天去邮局问,“有没有我的包裹啊”,运气好的话,有,你领回去了,运气不好,对不起接着坚持来问吧。于是,跑啊跑啊,累个半死不活。

    不过就你自己累,邮局无所谓,反正不用给你送货上门。

    但架不住人多啊,更多的像你一样的人有你那样的想法了,跑邮局,人多邮局就出问题了,每天只回答有没有包裹这个问题都忙到嘴没工夫闭上的地步,无法进行日常的发信和拍电报业务了。

    于是邮局崩溃了。

    这时,快递产生了。

    他们负责送货上门。住在城市中的人幸福了,不用跑邮局了。不过住在乡下的人还是郁闷,他们以为快递会平等对待给他们送货上门,也不跑邮局了,可等来等去,等到了一句话:乡下交通不便,恕不配送。。

    kao kao kao

     

    html5 WebSocket同样遇到了这样的尴尬。对IE,它只兼容10以及以上的版本(其它浏览器不考虑,IE是大户)。对于6789这些依旧没能淘汰掉的老古董,开发人员只能采用别的方式解决。

    有人说Nodejs可以。

    不错,确实可以。

    不过我想说的是,Nodejs的socket.io应该是判断了浏览器的兼容性之后做出的选择吧?支持web socket的采用websocket,不支持的采用别的方式(跑邮局)?

    工作也这么多年了,script一直是我的弱项。。。。

    虽然照猫画虎使用nodejs及socket.io写出了同样的功能,但心里总是没底。。。打脸-ing

    我说nodejs没别的意思,只是我不会。。。

    ***********************************************************分割线***********************************************************

    之前有看园子里的文章,知道使用Flash的socket可以解决兼容性的问题,但由于flex已经好几年没碰了,就没心思去搞。

    使用nodejs处理之后由于底气不足不敢在线上服务器用啊,于是转头copy别人的代码使用flash去解决socket问题,搞来搞去园友的文章不是抄别人的就是给出的flash是只适合自己用的,总也调试不通,干脆自己搞,也就是重拾一下as和flex而已。

    不多说废话了(打脸-ing),上代码吧。

    ***********************************************************分割线***********************************************************

    首先,创建Socket服务端,c#代码(我是使用Windows服务作Socket服务端,至于别的方式请自行脑补):

      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel;
      4 using System.Data;
      5 using System.Diagnostics;
      6 using System.Linq;
      7 using System.Net;
      8 using System.Net.Sockets;
      9 using System.Reflection;
     10 using System.ServiceProcess;
     11 using System.Text;
     12 using log4net;
     13 
     14 namespace YourNameSpace
     15 {
     16     partial class FlashSocket : ServiceBase
     17     {
     18         private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
     19         private static Socket server;
     20 
     21         private static Socket handSocket;
     22 
     23         private static string message = "testset";
     24         /// <summary>
     25         /// 需要维护的一个Socket Client集合
     26         /// </summary>
     27         private static List<Socket> Clients = new List<Socket>();
     28         public FlashSocket()
     29         {
     30             InitializeComponent();
     31         }
     32 
     33         protected override void OnStart(string[] args)
     34         {
     35             // TODO:  在此处添加代码以启动服务。
     36             CreateSocketServer();
     37             System.Timers.Timer tmr = new System.Timers.Timer();
     38             tmr.Interval = 1000 * 3;
     39             tmr.Elapsed += (sender, e) =>
     40             {
     41                 DoWork();
     42             };
     43             tmr.Start();
     44         }
     45 
     46 
     47         protected override void OnStop()
     48         {
     49             // TODO:  在此处添加代码以执行停止服务所需的关闭操作。
     50         }
     51 
     52         #region 创建Socket服务端
     53 
     54         private static void CreateSocketServer()
     55         {
     56             AllowDomain ad = new AllowDomain();
     57             server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     58             server.Bind(new IPEndPoint(IPAddress.Parse("192.168.5.134"), 2013));
     59             server.Listen(int.MaxValue);
     60             server.BeginAccept(InsertClientToCollection, server);
     61         }
     62         #endregion
     63         
     64         #region 有新客户端访问的时候添加进来
     65         /// <summary>
     66         /// 有新客户端访问的时候添加到客户端集合中
     67         /// </summary>
     68         /// <param name="ar"></param>
     69         private static void InsertClientToCollection(IAsyncResult ar)
     70         {
     71             try
     72             {
     73                 var socket = ar.AsyncState as Socket;
     74                 if (socket != null)
     75                 {
     76                     Clients.Add(socket.EndAccept(ar));
     77                     server.BeginAccept(InsertClientToCollection, server);
     78                     Logger.InfoFormat("新用户连接{0}", socket.LocalEndPoint);
     79                 }
     80             }
     81             catch (Exception ex)
     82             {
     83                 Logger.Error(ex);
     84             }
     85         }
     86 
     87         #endregion
     88         #region
     89         private void DoWork()
     90         {
     91             message = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "";
     92             try
     93             {
     94                 if (Clients.Count > 0)
     95                 {
     96                     var count = Clients.Count;
     97                     for (int i = 0; i < count; )
     98                     {
     99                         if (i < Clients.Count)
    100                         {
    101                             try
    102                             {
    103                                 Clients[i].Send(Encoding.UTF8.GetBytes(message));
    104                             }
    105                             catch (Exception)
    106                             {
    107                                 Clients.RemoveAt(i);
    108                                 i--;
    109                             }
    110                         }
    111                         i++;
    112                     }
    113                 }
    114                 if (Clients.Count > 0)
    115                     Logger.InfoFormat("当前客户端总数:{0}", Clients.Count);
    116             }
    117             catch (Exception ex)
    118             {
    119                 Logger.Error(ex);
    120             }
    121 
    122         }
    123         #endregion
    124 
    125     }
    126 }
    查看代码

    其中CreateSocketServer方法内有一句“AllowDomain ad = new AllowDomain();”,这个是解决flash安全沙箱跨域问题的,如果没有这句,flash读取socket数据的时候会报安全沙箱冲突。其实就是暴露Socket Server所在服务器的843端口给flash,以供握手(个人理解)。

    代码如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Net.Sockets;
     5 using System.Text;
     6 
     7 namespace YourNameSpace
     8 {
     9     public class AllowDomain
    10     {
    11         private TcpListener Server;
    12         private AsyncCallback callback;
    13         private bool islisten = false;
    14 
    15         public AllowDomain()
    16         {
    17             this.Server = new TcpListener(843);
    18             this.Server.Start();
    19             this.callback = new AsyncCallback(this.OnConnectionEvent);
    20             this.islisten = true;
    21             this.Server.BeginAcceptSocket(this.callback, null);
    22         }
    23 
    24         public void Close()
    25         {
    26             this.islisten = false;
    27             this.Server.Stop();
    28         }
    29 
    30         private void OnConnectionEvent(IAsyncResult syn)
    31     {
    32         if (this.islisten)
    33         {
    34             SocketError error;
    35             Socket conn = this.Server.EndAcceptSocket(syn);
    36             //conn.Send(PolicyFile.Policys);
    37             
    38             byte[] buffer = new byte[1024];
    39             int len = conn.Receive(buffer, 0, 1024, SocketFlags.None, out error);
    40             if (error == SocketError.Success)
    41             {
    42                 string s = Encoding.Default.GetString(buffer, 0, len);
    43                 if (s == "<policy-file-request/>")
    44                 {
    45                     buffer = Encoding.Default.GetBytes("<cross-domain-policy><allow-access-from domain="*" to-ports="2013"/></cross-domain-policy>");
    46                     conn.Send(buffer);
    47                 }
    48             }
    49             conn.Close();            
    50             if (this.islisten)
    51                 this.Server.BeginAcceptSocket(this.OnConnectionEvent, null);
    52         }
    53     }
    54     }
    55 }
    跨域

     下面是Flash代码,AS3:

     1 package
     2 {
     3     import flash.display.Sprite;
     4     import flash.events.Event;
     5     import flash.events.ProgressEvent;
     6     import flash.external.ExternalInterface;
     7     import flash.net.Socket;
     8     import flash.system.Security;
     9     import flash.utils.ByteArray;
    10     
    11     public class PushMessageLess extends Sprite
    12     {
    13         private var socket:Socket;
    14         private var msg:String="";
    15         protected function CreateSocket():void
    16         {
    17             Security.allowDomain("*");
    18             Security.loadPolicyFile("xmlsocket://192.168.5.134:843");
    19             
    20             // TODO Auto-generated method stub
    21             socket=new Socket();
    22             socket.connect("192.168.5.134",2013);
    23             socket.addEventListener(ProgressEvent.SOCKET_DATA,receivedMessage);
    24         }
    25         
    26         private function socketConnected(event:Event):void{
    27         }
    28         private function receivedMessage(e:ProgressEvent):void{
    29             var message:String="";
    30             while(socket.bytesAvailable){
    31                 message+=socket.readMultiByte(socket.bytesAvailable,"utf8");
    32             }
    33             msg=message;
    34             if(message.length>0){
    35                 callJs(message);
    36             }
    37         }
    38         
    39         private function callJs(m:String):void{
    40             ExternalInterface.call("callFlexFunction",m);
    41         }
    42         public function PushMessageLess()
    43         {
    44             if(stage){
    45                 CreateSocket();
    46             }else
    47             {
    48                 addEventListener(Event.ADDED_TO_STAGE,CreateSocket);
    49             }
    50         }
    51     }
    52 }
    Flash代码,注意,请修改后使用

    使用Flash Builder编译成swf文件PushMessageLess.swf(其实Less没有别的意思,是我原来用的是Flex项目,编译后把sdk中mx的部分东西编译进去了,比较大,有280k+,这个只有2k,可以接受)。

    这个文件名会在后面代码中用到,拿来主义者切记:用的时候改名字。

    下面是html代码:

     1 <html>
     2 <head>
     3     <title>测试Flash socket兼容IE6,7,8</title>
     4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     5     <script src="swfobject.js"></script>
     6 </head>
     7 
     8 <body>
     9 <script type="text/javascript">
    10     function callFlexFunction(msg) {
    11         if (msg != null) {
    12             document.getElementById("msgContainer").innerHTML = msg;
    13         }
    14     }
    15     var flashvars = false;
    16     var params = {};
    17     params.allowScriptAccess = "always";
    18     var attributes = {};
    19     //ID,也就是swf的ID,这个ID很重要,通过它调用flex的方法 
    20     attributes.id = "PushMessageLess";
    21 
    22     swfobject.embedSWF("PushMessageLess.swf?"+Math.random(), "PushMessageLess", "0", "0", "9.0.0","",flashvars,params,attributes);
    23 </script>
    24 <div id="PushMessageLess" style="display: none;"></div>
    25 <div id="msgContainer"></div>
    26 </body>
    27 </html>
    调用

    所需做的只是把上面生成的swf文件放到html同级目录下(当然,不放同级目录也可以,注意下html中的路径就可以了)。

    还有一个就是html页面中引用的一个swfObject.js,地址在这里

    swfObject.js

    就这么多了,希望各位少走弯路。

  • 相关阅读:
    技术周刊 · 耿耿星河欲曙天 | SpaceX 上的前端架构;跨平台新选择;开源世界的新“大门”;用户推荐算法的敲门砖……
    说说SVG的feTurbulence滤镜
    机器学习进阶
    小程序与动画的故事
    技术周刊 · 迢迢山径峻 | Web 开发成长图谱;下一代前端构建技术;AI 应用下支离破碎的真实;不懂产品不会开发;虚拟货币是新时代的黄金
    从中断机制看 React Fiber 技术
    三分钟了解数字人民币
    凹凸技术揭秘:如何服务 toG 项目——数字人民币项目前端总结
    使用 Phaser3+Matter.js 实现“合成大西瓜”游戏
    痞子衡嵌入式:快速定位i.MXRT600板级设计ISP[2:0]启动模式引脚上电时序问题的方法
  • 原文地址:https://www.cnblogs.com/panbao/p/5007319.html
Copyright © 2011-2022 走看看