zmqSocket.as 源码地址: http://zmqsocket-as.googlecode.com/svn/

zmqSocket.js 源码地址: http://zmqsocket-js.googlecode.com/svn/

zmqSocket.as是通过flex自带的socket在前端实现和后台消息通讯的一个简单类库,本来想简单配置下zmqSocket的使用,结果发现各种限制各种问题,整理出最后的使用规范和注意事项如下:

首先关于后台(小弟使用java编写的后台,其他语言这里仅供参考):

1、首先是跨域文件的获取,flex默认回去端口843寻找垮与文件,发送请求"<policy-file-request/>",并希望获得类似下列格式的跨域许可文件。

  1. <?xml version="1.0"?>
  2. <cross-domain-policy>
  3. <site-control permitted-cross-domain-policies="all"/>
  4. <allow-access-from domain="IP地址或*" to-ports="socket打开的端口" />
  5. </cross-domain-policy>

所以后台服务最好提供这样一个端口来专门负责处理

另外的一个解决方式是在客户端直接使用Security.loadPolicyFile(url); ,从指定的url去获取垮与文件。

关于跨域的内容可参考http://livedocs.adobe.com/flash/9.0_cn/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002106.html

2、关于服务端设置,因为socket是以二进制字节流传输信息的,所以要求服务端也应该是针字节流进行解析(xmlSocket貌似没有这样的问题,后面测测再补充下,如果大家有其他方案也可以告知我下,互相学习)。

*****服务端采用的方式,通过读取二进制数组,并将二进制数组接写成字符转来做最终的转义,写入的时候也是直接写入二进制字符串

附上一个java端实现许可文件提供的服务以供参考:

  1. import java.io.DataInputStream;
  2. import java.io.DataOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.ServerSocket;
  6. import java.net.Socket;
  7.  
  8. public class FlexServer2 {
  9. public static void main(String args[]) {
  10. try {
  11. DataInputStream din;
  12. DataOutputStream dout;
  13.  
  14. ServerSocket flexServer = new ServerSocket(843);
  15.  
  16. while (true) {
  17. Socket client = flexServer.accept();
  18. din = new DataInputStream(client.getInputStream());
  19. dout = new DataOutputStream(client.getOutputStream());
  20.  
  21. String s;
  22. String backFile = "<?xml version=\"1.0\"?>"
  23. + "<cross-domain-policy>"
  24. + "<site-control permitted-cross-domain-policies=\"all\"/>"
  25. + "<allow-access-from domain=\"*\" to-ports=\"*\" />"
  26. + "</cross-domain-policy>";
  27.  
  28. // 设置一个长度空间的二进制数组来获取客户端信息
  29. byte[] backBytes = backFile.getBytes("utf-8");
  30. while (true) {
  31. byte[] b = new byte[2048];
  32. int length = din.read(b, 0, b.length);
  33.  
  34. if (length != -1) {
  35. s = new String(b, 0, length);
  36. System.out.println("843读到的信息:" + s);
  37.  
  38. if (s.equals("<policy-file-request/>")) {
  39. dout.write(backBytes);
  40. dout.flush();
  41. } else {
  42. break;
  43. }
  44. }
  45. }
  46. din.close();
  47. dout.close();
  48. client.close();
  49. }
  50.  
  51. } catch (IOException e) {
  52. // TODO Auto-generated catch block
  53. e.printStackTrace();
  54. }
  55.  
  56. }
  57. }

服务端需要注意的也就这两点了,在客户端直接使用zmqSocket也有些严格要求的地方,细列如下:

客户端注意实现:

1、信息接收,提供类似事件回调的方式。 这点不同于习以为常的java或者c++代码,通过一个线程等待去轮询获取接收信息。(因为是flash是单线程的,如果等待意味着其他事都做不了了)。

比如直接使用socket,接收信息的办法是在  ProgressEvent.SOCKET_DATA 事件中去 判断bytesAvailable 并调用类似socket.readUTFBytes(bytesAvailable)的方法去获取信息。

关于直接使用socket的Demo请直接查看 Flex 4.0的API文档中的示例,很简单。

2、补充1. 关于zmqSocket中,内部添加一个关于信息的接收栈,只有当信息接收到足够多内容才会触发 Message 事件,(保留了跟socket默认的事件回调风格)也只有在这个时候嗲用recv()方法才能获取到信息。否则在下一次消息来临之后则会覆盖之前的信息。

关于这点要说明的是,当服务端信息过短的时候,是可能不会触发Message事件的,即意味着客户端可能没法立刻通过事件回调读取信息(关于这块应该是有可设置选项的,待研究吧)

给出一个直接使用zmqSocket.as的示范代码,来源于zmqSocket的官方测试代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  3. xmlns:s="library://ns.adobe.com/flex/spark"
  4. xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
  5. creationComplete="initSocket()"
  6. >
  7. <fx:Script>
  8. <![CDATA[
  9.  
  10. private function initSocket():void
  11. {
  12. var input: TextField = new TextField;
  13. input.type = TextFieldType.INPUT;
  14. input.background = true;
  15. input.border = true;
  16. input.width = 350;
  17. input.height = 350;
  18. ucom.addChild(input);
  19. input.appendText ("Starting\n");
  20.  
  21. try
  22. {
  23. var socket: ZmqSocket = new ZmqSocket ();
  24. }
  25. catch (e: Error)
  26. {
  27. input.appendText ("Error: " + e.toString ());
  28. return;
  29. }
  30.  
  31. socket.addEventListener (ZmqSocket.OPEN, function (e: Event)
  32. {
  33. input.appendText ("opened\n");
  34. socket.send (["", "Test"]);
  35. });
  36.  
  37. socket.addEventListener (ZmqSocket.MESSAGE, function (e: Event)
  38. {
  39. var msg: Array = socket.recv ();
  40. input.appendText (msg.length + "\n");
  41. if (msg.length > 1)
  42. input.appendText (msg[1] + "\n");
  43.  
  44. socket.send (["", "Test"]);
  45. });
  46.  
  47. socket.addEventListener (Event.CLOSE, function (e: Event)
  48. {
  49. input.appendText ("closed\n");
  50. });
  51.  
  52. socket.addEventListener (IOErrorEvent.IO_ERROR, function (e: IOErrorEvent)
  53. {
  54. input.appendText (e.toString ()+"\n");
  55. });
  56.  
  57. socket.addEventListener (SecurityErrorEvent.SECURITY_ERROR, function (e: SecurityErrorEvent)
  58. {
  59. input.appendText (e.toString ()+"\n");
  60. });
  61.  
  62. socket.connect ("localhost", 2000);
  63. }
  64.  
  65. ]]>
  66. </fx:Script>
  67. <s:layout>
  68. <s:BasicLayout/>
  69. </s:layout>
  70. <mx:UIComponent id="ucom"/>
  71. <fx:Declarations>
  72. <!-- 将非可视元素(例如服务、值对象)放在此处 -->
  73. </fx:Declarations>
  74. </s:Application>

3、追加3, 问题仍然是关于zmqSocket.as源码的。小弟下到的版本在信息发送时没有socket.flush() 这行代码的调用,导致服务端一直无法获得信息。补充后测试OK

注:这个在源码svn的的提交记录中是有过修改的,不知道为什么小弟这个版本没有,提醒大家遇到同样的问题可以自己修改下,重新编译swf,免得纠结...

总结,目前发现的问题就是上述了, 都是很小的细节,但很让人恼火..... 希望对大家有所帮助:

最后,简单实用as貌似不会太多,我们看看直接使用zmqSocket.js的,这里是通过客户端js与as的交互,来实现第一个普通网页的请求处理。

这里直接使用官方获取到的示例代码。zmqSocket和zmqSocketMain源码重新编译,生成新的zmqSocketMain.swf文件。配合上述的服务端代码测试,OK!!!O(∩_∩)O~

注意:发现的小问题,在本地直接双击打开网页的时候可能会有ExternalInterface.calll方法跨域错误。  解决方案1:修改flashPlayerTrust文件下的配置。2:发布网页通过ip地址访问测试

示范代码如下:

  1. //////////file zmqSocket.js
  2. (function()
  3. {
  4. // Check if module is already initialized.
  5. if (window.ZmqSocket)
  6. return;
  7.  
  8. // Constructor. You may pass socket identity here.
  9. ZmqSocket = function(identity)
  10. {
  11. this.fd = ZmqSocket.__nextFd++;
  12. ZmqSocket.__sockets[this.fd] = this;
  13.  
  14. this.identity = identity;
  15. this.state = ZmqSocket.CONNECTING;
  16. this.onopen = function() {
  17. };
  18. this.onmessage = function() {
  19. };
  20. this.onerror = function(msg) {
  21. };
  22. this.onclose = function() {
  23. };
  24.  
  25. var athis = this;
  26. ZmqSocket.__addTask(function()
  27. {
  28. ZmqSocket.__flash.create(athis.fd, athis.identity);
  29. });
  30. };
  31.  
  32. ZmqSocket.__sockets = [];
  33. ZmqSocket.__tasks = [];
  34. ZmqSocket.__nextFd = 0;
  35. ZmqSocket.__flash = null;
  36.  
  37. ZmqSocket.CONNECTING = 1;
  38. ZmqSocket.OPEN = 2;
  39. ZmqSocket.CLOSING = 3;
  40.  
  41. // Called by Flash when it's ready.
  42. ZmqSocket.__onFlashReady = function()
  43. {
  44. if (navigator.appName.indexOf("Microsoft") != -1)
  45. ZmqSocket.__flash = window["ZmqSocketFlash"];
  46. else
  47. ZmqSocket.__flash = document["ZmqSocketFlash"];
  48.  
  49. // Make it later to avoid recursion.
  50. ZmqSocket.__later(function()
  51. {
  52. for (var i = 0; i < ZmqSocket.__tasks.length; i++)
  53. ZmqSocket.__tasks[i]();
  54. });
  55. };
  56.  
  57. // Used to make calls in a separate event handler to avoid
  58. // recursive calls to Flash - recursion is not supported by many browsers.
  59. ZmqSocket.__later = function(task)
  60. {
  61. var to = setTimeout(function() {
  62. clearTimeout(to);
  63. task();
  64. }, 0);
  65. }
  66.  
  67. // Called by Flash to find out if JS is ready.
  68. ZmqSocket.__isJSReady = function() {
  69. return true;
  70. };
  71.  
  72. // Called when we are not sure that flash is ready.
  73. ZmqSocket.__addTask = function(task)
  74. {
  75. if (ZmqSocket.__flash)
  76. task();
  77. else
  78. ZmqSocket.__tasks.push(task);
  79. }
  80.  
  81. ZmqSocket.prototype.connect = function(host, port)
  82. {
  83. var athis = this;
  84. ZmqSocket.__addTask(function()
  85. {
  86. ZmqSocket.__flash.connect(athis.fd, host, port);
  87. });
  88. }
  89.  
  90. ZmqSocket.prototype.close = function()
  91. {
  92. this.state = ZmqSocket.CLOSING;
  93. var athis = this;
  94. ZmqSocket.__addTask(function()
  95. {
  96. alert('before');
  97. ZmqSocket.__flash.close(athis.fd);
  98. alert('after');
  99. });
  100. }
  101.  
  102. ZmqSocket.prototype.available = function()
  103. {
  104. if (this.state != ZmqSocket.OPEN)
  105. throw "Invalid state, socket must be connected!";
  106.  
  107. return ZmqSocket.__flash.available(this.fd);
  108. }
  109.  
  110. ZmqSocket.prototype.recv = function()
  111. {
  112. if (this.state != ZmqSocket.OPEN)
  113. throw "Invalid state, socket must be connected!";
  114.  
  115. return ZmqSocket.__flash.recv(this.fd);
  116. }
  117.  
  118. ZmqSocket.prototype.send = function(msg)
  119. {
  120. if (this.state != ZmqSocket.OPEN)
  121. throw "Invalid state, socket must be connected!";
  122.  
  123. return ZmqSocket.__flash.send(this.fd, msg);
  124. }
  125.  
  126. ZmqSocket.__onopen = function(fd)
  127. {
  128. // Avoiding recursion
  129. ZmqSocket.__later(function()
  130. {
  131. ZmqSocket.__sockets[fd].state = ZmqSocket.OPEN;
  132. ZmqSocket.__sockets[fd].onopen();
  133. });
  134. }
  135.  
  136. ZmqSocket.__onmessage = function(fd)
  137. {
  138. // Avoiding recursion
  139. ZmqSocket.__later(function() {
  140. ZmqSocket.__sockets[fd].onmessage();
  141. });
  142. }
  143.  
  144. ZmqSocket.__onerror = function(fd, msg)
  145. {
  146. // Avoiding recursion
  147. ZmqSocket.__later(function() {
  148. ZmqSocket.__sockets[fd].onerror(msg);
  149. });
  150. }
  151.  
  152. ZmqSocket.__onclose = function(fd)
  153. {
  154. // Avoiding recursion
  155. ZmqSocket.__later(function() {
  156. ZmqSocket.__sockets[fd].onclose();
  157. });
  158. }
  159.  
  160. })();

 

  1. /////////file Test.html
  2.  
  3. <html>
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6. <title>ZmqSocket.js</title>
  7. <script language="JavaScript" src='ZmqSocket.js'>
  8. </script>
  9. </head>
  10. <body>
  11.  
  12. <script language="JavaScript">
  13.  
  14. var socket = new ZmqSocket();
  15. var ready = false;
  16.  
  17. socket.onopen = function() {
  18. ready = true;
  19. };
  20. socket.onmessage = function() {
  21. if (socket.available()) {
  22. var m = socket.recv();
  23. alert(m);
  24. } else {
  25. alert('Assertion failure!');
  26. }
  27. };
  28. socket.onclose = function() {
  29. alert('close');
  30. };
  31. socket.onerror = function(msg) {
  32. alert(msg);
  33. };
  34.  
  35. socket.connect("localhost", 2000);
  36. </script>
  37.  
  38. <input type='text' id='in' />
  39. <input type='submit' value='Send' onclick='if (!ready) return; var t = document.getElementById("in").value; socket.send (["", t]); ' />
  40.  
  41. <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  42. id="ZmqSocketFlash" width="0" height="0"
  43. codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  44. <param name="movie" value="ZmqSocketMain.swf" />
  45. <param name="allowScriptAccess" value="sameDomain" />
  46. <embed src="ZmqSocketMain.swf" quality="high"
  47. width="0" height="0" name="ZmqSocketFlash" align="middle"
  48. play="true" loop="false" allowScriptAccess="sameDomain"
  49. type="application/x-shockwave-flash"
  50. pluginspage="http://www.macromedia.com/go/getflashplayer">
  51. </embed>
  52. </object>
  53.  
  54. </body>
  55. </html>

  

zmqSocket 使用和相关java后台准备的更多相关文章

  1. Java后台工程师面试杂记——不跳不涨工资星人跳槽经历

    经过接近一个月的时间,完成换工作这件“小事”,前后总计面试了多家公司,最后也没接到几个offer,不过最终总算尘埃落定,就对这个过程进行一个总结吧. 在某互联网公司工作了近一年的时间,但是频繁的业务需 ...

  2. 你不可错过的二维码生成与解析-java后台与前端js都有

    1.二维码分类   二维条码也有许多不同的码制,就码制的编码原理而言,通常分为三种类型. 线性堆叠式二维码 编码原理: 建立在一维条码基础之上,按需要堆积成两行或多行. 图示: 矩阵式二维码 最常用编 ...

  3. 如何用CropBox实现头像裁剪并与java后台交互

    如何用CropBox实现头像裁剪并与java后台交互 参考网站:https://developer.mozilla.org/zh-CN/docs/Web/API/Blob 参考: http://blo ...

  4. 美团、java后台实习、面经

    3月27号投了美团java后台,29号收到面试邀请,好像是金融服务平台(提交简历的时候,我当时没注意随便填的···) 一面: 介绍项目经历 根据简历问一些问题:比如我简历上有区块链相关,会要求介绍一下 ...

  5. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

  6. java后台常用json解析工具问题小结

    若排版紊乱可查看我的个人博客原文地址 java后台常用json解析工具问题小结 这里不细究造成这些问题的底层原因,只是单纯的描述我碰到的问题及对应的解决方法 jackson将java对象转json字符 ...

  7. 终于,我还是下决心学Java后台了

    我没有什么本事,人也丑,也不会忽悠,只能硬着头皮学习了.最近计划学习Java后台,因为最近接了私活的问题,好多都要Java后台和前端一起做.平常我在做什么,当然是忙着赚钱了 除了敲代码,你还有什么副业 ...

  8. Java 后台验证的工具类

    Java 后台验证的工具类 public class ValidationUtil {         //手机号     public static String mobile = "^( ...

  9. 微信小程序与java后台交互

    java后台使用的ssm框架,小程序连接的本地接口.跟正常的web访问没什么区别,也是后台获取url,返回json数据:只是小程序前台请求的url要带上http://localhost:80801. ...

随机推荐

  1. Codeforces Gym100952 C. Palindrome Again !!-回文字符串 (2015 HIAST Collegiate Programming Contest)

      C. Palindrome Again !!   time limit per test 1 second memory limit per test 64 megabytes input sta ...

  2. HDU-6315 Naive Operations//2018 Multi-University Training Contest 2___1007 (线段树,区间除法)

    原题地址 Naive Operations Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/ ...

  3. (寒假集训)Roadblock(最短路)

    Roadblock 时间限制: 1 Sec  内存限制: 64 MB提交: 9  解决: 5[提交][状态][讨论版] 题目描述 Every morning, FJ wakes up and walk ...

  4. Super Ugly Number -- LeetCode

    Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...

  5. Oracle PL/SQL DBA 编程实践基础

    [附:一文一图]

  6. /usr/local/lib/libz.a: could not read symbols: Bad value(64 位 Linux)

    /usr/local/lib/libz.a: could not read symbols: Bad value(64 位 Linux) /usr/bin/ld: /usr/local/lib/lib ...

  7. Android简单文件浏览器源代码 (转)

    Android简单文件浏览器源代码 (转) activity_main .xml <LinearLayout xmlns:android="http://schemas.android ...

  8. dragon-book-exercise-answers

    https://github.com/fool2fish/dragon-book-exercise-answers

  9. Android简单的利用SoundPool进行播放铃声的实例代码

    MainActivity.java package com.example.pengdonglin.soundpool_demo; import android.annotation.Suppress ...

  10. 【spring boot】集成了druid后,同样的mybatis模糊查询语句出错Caused by: com.alibaba.druid.sql.parser.ParserException: syntax error, error in :'name LIKE '%' ? '%'

    druid版本是 <!-- https://mvnrepository.com/artifact/com.alibaba/druid 数据库连接池--> <dependency> ...