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去获取垮与文件。

关于跨域的内容可参考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端实现许可文件提供的服务以供参考:

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>

  

最新文章

  1. Iterm2 ssh tab title
  2. iOS中修改头部tabBarButton 默认按钮的颜色和默认字体颜色
  3. EC笔记,第一部分:3.尽量使用const
  4. sdut 2125串结构练习--字符串匹配【两种KMP算法】
  5. hdu4686 Arc of Dream ——构造矩阵+快速幂
  6. Ubuntu 15.10安装elementary desktop
  7. 开启xp_cmdshell
  8. window7 下 安装 apache24(httpd-2.4.10-x86-r2)加 php5.6(php-5.6.4-Win32-VC11-x86)加yaf(php_yaf-2.3.3-5.6-ts-vc11-x86)整合
  9. (六)C#中判断空字符串的三种方法性能分析
  10. vs2008工程配置
  11. 从51跳cortex-m0学习2——程序详解
  12. SpringMVC入门二: 1规范结构, 2简单整合MyBatis
  13. Linux系统安全需要注意的一些问题
  14. 译:Missing index DMV的 bug可能会使你失去理智---慎重看待缺失索引DMV中的信息
  15. ajax返回json数据示例
  16. 结对编程四则运算gui
  17. MySQL GTID复制Slave跳过错误事务Id以及复制排错问题总结
  18. Servlet中的jsp内置对象
  19. JavaScript原型、闭包、继承和原型链等等总结
  20. row_number() over() 一句话概括,以及max()函数的一种查询分组中最大值的用法

热门文章

  1. Js 利用正则表达式和replace函数获取string中所有被匹配到的文本
  2. HDU 6336 子矩阵求和
  3. 华农oj Problem L: CreatorX背英语【STL】
  4. Codeforces 825F - String Compression
  5. 分层图【p2939】[USACO09FEB]改造路Revamping Trails
  6. HDU 5916: Harmonic Value Description
  7. Walls and Gates -- LeetCode
  8. steelray project viewer
  9. 第七章 android-UI组件
  10. 集合框架(02)List