zmqSocket 使用和相关java后台准备
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/>",并希望获得类似下列格式的跨域许可文件。
- <?xml version="1.0"?>
- <cross-domain-policy>
- <site-control permitted-cross-domain-policies="all"/>
- <allow-access-from domain="IP地址或*" to-ports="socket打开的端口" />
- </cross-domain-policy>
所以后台服务最好提供这样一个端口来专门负责处理
另外的一个解决方式是在客户端直接使用Security.loadPolicyFile(url); ,从指定的url去获取垮与文件。
2、关于服务端设置,因为socket是以二进制字节流传输信息的,所以要求服务端也应该是针字节流进行解析(xmlSocket貌似没有这样的问题,后面测测再补充下,如果大家有其他方案也可以告知我下,互相学习)。
*****服务端采用的方式,通过读取二进制数组,并将二进制数组接写成字符转来做最终的转义,写入的时候也是直接写入二进制字符串
附上一个java端实现许可文件提供的服务以供参考:
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.ServerSocket;
- import java.net.Socket;
- public class FlexServer2 {
- public static void main(String args[]) {
- try {
- DataInputStream din;
- DataOutputStream dout;
- ServerSocket flexServer = new ServerSocket(843);
- while (true) {
- Socket client = flexServer.accept();
- din = new DataInputStream(client.getInputStream());
- dout = new DataOutputStream(client.getOutputStream());
- String s;
- String backFile = "<?xml version=\"1.0\"?>"
- + "<cross-domain-policy>"
- + "<site-control permitted-cross-domain-policies=\"all\"/>"
- + "<allow-access-from domain=\"*\" to-ports=\"*\" />"
- + "</cross-domain-policy>";
- // 设置一个长度空间的二进制数组来获取客户端信息
- byte[] backBytes = backFile.getBytes("utf-8");
- while (true) {
- byte[] b = new byte[2048];
- int length = din.read(b, 0, b.length);
- if (length != -1) {
- s = new String(b, 0, length);
- System.out.println("843读到的信息:" + s);
- if (s.equals("<policy-file-request/>")) {
- dout.write(backBytes);
- dout.flush();
- } else {
- break;
- }
- }
- }
- din.close();
- dout.close();
- client.close();
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
服务端需要注意的也就这两点了,在客户端直接使用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的官方测试代码:
- <?xml version="1.0" encoding="utf-8"?>
- <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
- xmlns:s="library://ns.adobe.com/flex/spark"
- xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
- creationComplete="initSocket()"
- >
- <fx:Script>
- <![CDATA[
- private function initSocket():void
- {
- var input: TextField = new TextField;
- input.type = TextFieldType.INPUT;
- input.background = true;
- input.border = true;
- input.width = 350;
- input.height = 350;
- ucom.addChild(input);
- input.appendText ("Starting\n");
- try
- {
- var socket: ZmqSocket = new ZmqSocket ();
- }
- catch (e: Error)
- {
- input.appendText ("Error: " + e.toString ());
- return;
- }
- socket.addEventListener (ZmqSocket.OPEN, function (e: Event)
- {
- input.appendText ("opened\n");
- socket.send (["", "Test"]);
- });
- socket.addEventListener (ZmqSocket.MESSAGE, function (e: Event)
- {
- var msg: Array = socket.recv ();
- input.appendText (msg.length + "\n");
- if (msg.length > 1)
- input.appendText (msg[1] + "\n");
- socket.send (["", "Test"]);
- });
- socket.addEventListener (Event.CLOSE, function (e: Event)
- {
- input.appendText ("closed\n");
- });
- socket.addEventListener (IOErrorEvent.IO_ERROR, function (e: IOErrorEvent)
- {
- input.appendText (e.toString ()+"\n");
- });
- socket.addEventListener (SecurityErrorEvent.SECURITY_ERROR, function (e: SecurityErrorEvent)
- {
- input.appendText (e.toString ()+"\n");
- });
- socket.connect ("localhost", 2000);
- }
- ]]>
- </fx:Script>
- <s:layout>
- <s:BasicLayout/>
- </s:layout>
- <mx:UIComponent id="ucom"/>
- <fx:Declarations>
- <!-- 将非可视元素(例如服务、值对象)放在此处 -->
- </fx:Declarations>
- </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地址访问测试
示范代码如下:
- //////////file zmqSocket.js
- (function()
- {
- // Check if module is already initialized.
- if (window.ZmqSocket)
- return;
- // Constructor. You may pass socket identity here.
- ZmqSocket = function(identity)
- {
- this.fd = ZmqSocket.__nextFd++;
- ZmqSocket.__sockets[this.fd] = this;
- this.identity = identity;
- this.state = ZmqSocket.CONNECTING;
- this.onopen = function() {
- };
- this.onmessage = function() {
- };
- this.onerror = function(msg) {
- };
- this.onclose = function() {
- };
- var athis = this;
- ZmqSocket.__addTask(function()
- {
- ZmqSocket.__flash.create(athis.fd, athis.identity);
- });
- };
- ZmqSocket.__sockets = [];
- ZmqSocket.__tasks = [];
- ZmqSocket.__nextFd = 0;
- ZmqSocket.__flash = null;
- ZmqSocket.CONNECTING = 1;
- ZmqSocket.OPEN = 2;
- ZmqSocket.CLOSING = 3;
- // Called by Flash when it's ready.
- ZmqSocket.__onFlashReady = function()
- {
- if (navigator.appName.indexOf("Microsoft") != -1)
- ZmqSocket.__flash = window["ZmqSocketFlash"];
- else
- ZmqSocket.__flash = document["ZmqSocketFlash"];
- // Make it later to avoid recursion.
- ZmqSocket.__later(function()
- {
- for (var i = 0; i < ZmqSocket.__tasks.length; i++)
- ZmqSocket.__tasks[i]();
- });
- };
- // Used to make calls in a separate event handler to avoid
- // recursive calls to Flash - recursion is not supported by many browsers.
- ZmqSocket.__later = function(task)
- {
- var to = setTimeout(function() {
- clearTimeout(to);
- task();
- }, 0);
- }
- // Called by Flash to find out if JS is ready.
- ZmqSocket.__isJSReady = function() {
- return true;
- };
- // Called when we are not sure that flash is ready.
- ZmqSocket.__addTask = function(task)
- {
- if (ZmqSocket.__flash)
- task();
- else
- ZmqSocket.__tasks.push(task);
- }
- ZmqSocket.prototype.connect = function(host, port)
- {
- var athis = this;
- ZmqSocket.__addTask(function()
- {
- ZmqSocket.__flash.connect(athis.fd, host, port);
- });
- }
- ZmqSocket.prototype.close = function()
- {
- this.state = ZmqSocket.CLOSING;
- var athis = this;
- ZmqSocket.__addTask(function()
- {
- alert('before');
- ZmqSocket.__flash.close(athis.fd);
- alert('after');
- });
- }
- ZmqSocket.prototype.available = function()
- {
- if (this.state != ZmqSocket.OPEN)
- throw "Invalid state, socket must be connected!";
- return ZmqSocket.__flash.available(this.fd);
- }
- ZmqSocket.prototype.recv = function()
- {
- if (this.state != ZmqSocket.OPEN)
- throw "Invalid state, socket must be connected!";
- return ZmqSocket.__flash.recv(this.fd);
- }
- ZmqSocket.prototype.send = function(msg)
- {
- if (this.state != ZmqSocket.OPEN)
- throw "Invalid state, socket must be connected!";
- return ZmqSocket.__flash.send(this.fd, msg);
- }
- ZmqSocket.__onopen = function(fd)
- {
- // Avoiding recursion
- ZmqSocket.__later(function()
- {
- ZmqSocket.__sockets[fd].state = ZmqSocket.OPEN;
- ZmqSocket.__sockets[fd].onopen();
- });
- }
- ZmqSocket.__onmessage = function(fd)
- {
- // Avoiding recursion
- ZmqSocket.__later(function() {
- ZmqSocket.__sockets[fd].onmessage();
- });
- }
- ZmqSocket.__onerror = function(fd, msg)
- {
- // Avoiding recursion
- ZmqSocket.__later(function() {
- ZmqSocket.__sockets[fd].onerror(msg);
- });
- }
- ZmqSocket.__onclose = function(fd)
- {
- // Avoiding recursion
- ZmqSocket.__later(function() {
- ZmqSocket.__sockets[fd].onclose();
- });
- }
- })();
- /////////file Test.html
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>ZmqSocket.js</title>
- <script language="JavaScript" src='ZmqSocket.js'>
- </script>
- </head>
- <body>
- <script language="JavaScript">
- var socket = new ZmqSocket();
- var ready = false;
- socket.onopen = function() {
- ready = true;
- };
- socket.onmessage = function() {
- if (socket.available()) {
- var m = socket.recv();
- alert(m);
- } else {
- alert('Assertion failure!');
- }
- };
- socket.onclose = function() {
- alert('close');
- };
- socket.onerror = function(msg) {
- alert(msg);
- };
- socket.connect("localhost", 2000);
- </script>
- <input type='text' id='in' />
- <input type='submit' value='Send' onclick='if (!ready) return; var t = document.getElementById("in").value; socket.send (["", t]); ' />
- <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
- id="ZmqSocketFlash" width="0" height="0"
- codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
- <param name="movie" value="ZmqSocketMain.swf" />
- <param name="allowScriptAccess" value="sameDomain" />
- <embed src="ZmqSocketMain.swf" quality="high"
- width="0" height="0" name="ZmqSocketFlash" align="middle"
- play="true" loop="false" allowScriptAccess="sameDomain"
- type="application/x-shockwave-flash"
- pluginspage="http://www.macromedia.com/go/getflashplayer">
- </embed>
- </object>
- </body>
- </html>
zmqSocket 使用和相关java后台准备的更多相关文章
- Java后台工程师面试杂记——不跳不涨工资星人跳槽经历
经过接近一个月的时间,完成换工作这件“小事”,前后总计面试了多家公司,最后也没接到几个offer,不过最终总算尘埃落定,就对这个过程进行一个总结吧. 在某互联网公司工作了近一年的时间,但是频繁的业务需 ...
- 你不可错过的二维码生成与解析-java后台与前端js都有
1.二维码分类 二维条码也有许多不同的码制,就码制的编码原理而言,通常分为三种类型. 线性堆叠式二维码 编码原理: 建立在一维条码基础之上,按需要堆积成两行或多行. 图示: 矩阵式二维码 最常用编 ...
- 如何用CropBox实现头像裁剪并与java后台交互
如何用CropBox实现头像裁剪并与java后台交互 参考网站:https://developer.mozilla.org/zh-CN/docs/Web/API/Blob 参考: http://blo ...
- 美团、java后台实习、面经
3月27号投了美团java后台,29号收到面试邀请,好像是金融服务平台(提交简历的时候,我当时没注意随便填的···) 一面: 介绍项目经历 根据简历问一些问题:比如我简历上有区块链相关,会要求介绍一下 ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
- java后台常用json解析工具问题小结
若排版紊乱可查看我的个人博客原文地址 java后台常用json解析工具问题小结 这里不细究造成这些问题的底层原因,只是单纯的描述我碰到的问题及对应的解决方法 jackson将java对象转json字符 ...
- 终于,我还是下决心学Java后台了
我没有什么本事,人也丑,也不会忽悠,只能硬着头皮学习了.最近计划学习Java后台,因为最近接了私活的问题,好多都要Java后台和前端一起做.平常我在做什么,当然是忙着赚钱了 除了敲代码,你还有什么副业 ...
- Java 后台验证的工具类
Java 后台验证的工具类 public class ValidationUtil { //手机号 public static String mobile = "^( ...
- 微信小程序与java后台交互
java后台使用的ssm框架,小程序连接的本地接口.跟正常的web访问没什么区别,也是后台获取url,返回json数据:只是小程序前台请求的url要带上http://localhost:80801. ...
随机推荐
- 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 ...
- 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/ ...
- (寒假集训)Roadblock(最短路)
Roadblock 时间限制: 1 Sec 内存限制: 64 MB提交: 9 解决: 5[提交][状态][讨论版] 题目描述 Every morning, FJ wakes up and walk ...
- Super Ugly Number -- LeetCode
Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...
- Oracle PL/SQL DBA 编程实践基础
[附:一文一图]
- /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 ...
- Android简单文件浏览器源代码 (转)
Android简单文件浏览器源代码 (转) activity_main .xml <LinearLayout xmlns:android="http://schemas.android ...
- dragon-book-exercise-answers
https://github.com/fool2fish/dragon-book-exercise-answers
- Android简单的利用SoundPool进行播放铃声的实例代码
MainActivity.java package com.example.pengdonglin.soundpool_demo; import android.annotation.Suppress ...
- 【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> ...