让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") + "\0";
 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/>\0")
44                 {
45                     buffer = Encoding.Default.GetBytes("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"2013\"/></cross-domain-policy>\0");
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

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

转载于:https://www.cnblogs.com/panbao/p/5007319.html

### 回答1: Servlet和WebSocket都是Java Web开发中常用的技术。 Servlet是一种运行在Web服务器上的Java程序,用于处理HTTP请求和响应。Servlet可以接收HTTP请求,并根据请求的类型执行相应的逻辑。开发人员可以通过继承Servlet类来编写自己的Servlet,也可以通过注解的方式将Servlet映射到特定的URL路径。 WebSocket是一种实现了双向通信的网络协议,它可以在浏览器和服务器之间建立持久连接,并且可以在任意时刻进行数据交换。相比于传统的HTTP请求响应模型,WebSocket具有更低的延迟和更高的实时性,适合用于实时通信和数据推送场景。 在Java Web开发中,开发人员可以使用Java WebSocket API来实现WebSocket功能,也可以使用第三方的WebSocket库来简化开发。在使用WebSocket时,通常需要在服务器端实现一个WebSocket端点(WebSocket Endpoint),用于接收和处理WebSocket连接的请求,并且可以通过Session对象与客户端进行通信。 ### 回答2: Servlet和WebSocket是Java用于开发Web应用程序的两种技术。 Servlet是Java编写的服务器端程序,用于接收和处理来自客户端的HTTP请求,并生成响应返回给客户端。Servlet通常用于动态生成HTML页面或处理来自表单的数据。它可以接受客户端的请求参数,读取和写入Session的数据,并与数据库进行交互。Servlet可以在Web容器中运行,如Tomcat或Jetty。 WebSocket是一种在Web应用程序中实现实时双向通信的协议。它允许服务器主动向客户端推送消息,并允许客户端向服务器发送消息。相比于传统的HTTP请求-响应模式,WebSocket在单个连接上提供持久的双向通信。它使用了更轻量的协议和更小的数据包,从而减少了服务器和客户端之间的通信开销。WebSocket可以用于实时的聊天应用程序、实时协作工具、多人在线游戏等。 与Servlet相比,WebSocket提供了更实时的通信能力,并且可以在服务端主动推送数据给客户端。Servlet只能在客户端发送请求时才能进行响应。另外,WebSocket可以通过保持连接状态来节省网络带宽和服务器资源,而Servlet每次请求和响应都需要建立和关闭连接。但是,由于WebSocket是一种新的技术,需要浏览器和服务器的支持。一些较旧的浏览器可能不支持WebSocket,因此在开发Web应用程序时需要考虑兼容性问题。 综上所述,Servlet和WebSocket都是用于开发Java Web应用程序的技术,Servlet用于处理HTTP请求和生成响应,而WebSocket实现了实时的双向通信,提供了更实时的通信能力。两者在不同场景下可以互补使用,根据具体的需求选择合适的技术。 ### 回答3: Servlet是Java编程语言的一个标准,用于服务器端编程。它允许开发人员在服务器上处理客户端请求和生成动态网页。Servlet运行在Web容器中,与Web服务器协作,如Apache Tomcat。Servlet通过HTTP协议接收和响应客户端请求,并具有处理表单数据、访问数据库、生成动态网页等功能。 Web Socket是HTML5规范的一部分,它提供了一种在Web浏览器和服务器之间进行实时双向通信的机制。与传统的HTTP请求-响应模型不同,Web Socket允许服务器主动向客户端发送消息,而不需要客户端发起请求。这使得实时的、互动式的应用程序变得更容易开发和实现。 Servlet和Web Socket在不同的场景中有不同的用途。Servlet适用于传统的请求-响应模型,通过处理客户端请求来生成动态网页或提供服务。Servlet可以处理各种类型的HTTP请求,如GET、POST等,并能够以客户端需求为基础生成动态内容。 Web Socket则更适合实时的、互动式的应用程序,如聊天应用、在线游戏等。与Servlet不同,Web Socket建立起的是一个持久的连接,服务器和客户端之间可以随时互相发送消息。这种双向通信机制使得实时性要求较高的应用程序变得更为简单。 综上所述,Servlet和Web Socket是两种不同的技术,适用于不同的场景。Servlet用于处理传统的请求-响应模型,生成动态网页或提供服务;而Web Socket用于实现实时的、双向通信的应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值