众所周知Flash的功能比较强大,但是有两个功能到目前为止始终无法实现 1是swf的点对点连接 2是swf读写操作文件别想了,靠Flash本身是不可能的, 虽然有传说中的MMSave();等一些隐藏函数,但是毕竟这些未公开的函数了解的人并不多,用起来也不方便。那么究竟有没有其他办法可以扶助实现呢?答 案当然是肯定的。在这里我们需要请出当前最热的两门名副其实的编程语言C++/Java,靠他们来实现你要实现的功能吧。在这里我用Java举 例。 首先我们必须了解 AS如何让Java做事?对于双方来讲唯一应用性最高的途径就是Socket了。 AS1->XMLSocket->send()->Java.Socket->InputStream AS2->XMLSocket->send()->Java.Socket->InputStream AS3->Socket->writh()->flush()->Java.Socket->InputStream as1&2只支持以字符串形式发送socket,而as3支持真正意义上的流,在这里为了兼容和教学简单,我均以字符串形式来实现相互间的通信。 1->AS与Java最基本的通信 1.1 简单Java服务器首先我们来做最简单的单线程Java服务器
import java.io.*; import java.net.*; public class Server extends ServerSocket{ //服务端口号常量(as要求必须大于1024,小于65535) private static final int SERVER_PORT = 10086; //申明流的空间 private Socket client; private BufferedReader in; private PrintWriter out; private String src; //构造函数 public Server() throws IOException{ super(SERVER_PORT); //监听连接,初始流在进来后读取前,和写入后发送前所存放的空间 Socket socket = accept(); in = new BufferedReader(new InputStreamReader(client.getInputStream())); out = new PrintWriter(client.getOutputStream(),true); //循环等待读取信息 while(true){ //读取行信息,注意是以换行符结束的 src = in.readLine(); //如果发送"close",就跳出循环(断开连接) if(src.equals("close")){ break; } //在收到的信息前加是标识并发回(注意结尾加"\0",这是as的XMLSocket读入每条信息的条件.as3的Socket不需要) out.println("rev: "+src+"\0"); //以上out.println("xx")相当于out.write("xx");out.flush();的执行效果 System.out.println("msg is "+src) } //关闭连接 close(); } //入口函数... public static void main (String[] args) throws IOException{ new Server(); } }
这样一个Java的服务器就建好了,Java是同步的事件的驱动是等待的,这个AS是不同的,所以方法对与as区别还是比较大的,具体功能已经注释 的非常清楚。至于具体Java的特性我不是专业的,为了对读者负责我就不做详细介绍了,有兴趣的朋友可以查阅Java相关书籍。接下来呢就是AS的访问 了: 1.2 AS1 与 Java 通信 Action Script 1
var SERVER_PORT = 10086; var SERVER_IP = "127.0.0.1"; var conn = new XMLSocket(); conn.connect(SERVER_IP,SERVER_PORT); conn.onConnect = socketConnect; conn.onData = socketData; function socketConnect(success){ trace("connect"+success); if(success){ this.send("hello world\r"); } } function socketData(src){ trace(src); }
接触了相对生疏的Java后现在回到AS,感觉就是爽,嘿嘿前三行定义了三个变量,由于as1没有强制类型,所以千万别加上类型修饰符啊,反而会出 错,请注意。 conn.connect(SERVER_IP,SERVER_PORT);连接到socket的服务器。如果连接成功 Java中的 ServerSocket.accept();会返回一个对象,并向下执行。 as的连接成功呢则触发了socketConnect(success)的事件,并且把true的参数传如函数。当然连不到就是false了。成功后就会 发送一个"hello world\r"的字符串,"\r"是回车符,因为Java里我用的是readLine();所以需要看到行的结束。当有数据进来的时候呢就会出发 socketData函数了,这里把信息输出。好了用as1的朋友到此已经成功与Java程序通讯了。 1.3 AS2 与 Java 通信 Action Script 2
var SERVER_PORT:Number = 10086; var SERVER_IP:String = "127.0.0.1"; var conn:XMLSocket = new XMLSocket(); conn.connect(SERVER_IP,SERVER_PORT); conn.onConnect = socketConnect; conn.onData = socketData; function socketConnect(success:Boolean){ trace("connect"+success); if(success){ this.send("hello world\r"); } } function socketData(src:String){ trace(src); }
以上是fla版,和as1唯一的区别就是有类型定义,这样做无论是时间执行效率还是空间执行效率都会有明显提高。接下去看看真正的Action Script 2代码,将以下代码保存成Socket.as文件,和fla文件放在一起。
class Socket extends XMLSocket{ public function Socket(){ super(); } public function onConnect(success:Boolean){ trace("connect"+success); if (success){ this.send("hello world\r"); } } public function onData(src:String){ trace(src); } }
fla里在帧上写
var SERVER_PORT:Number = 10086; var SERVER_IP:String = "127.0.0.1"; var conn:Socket = new Socket(); conn.connect(SERVER_IP,SERVER_PORT);
这才是真正的as2,当然你可以更好的修改Socket,让他符合Server的要求,比如在类里加上一个常量,并写入符合Server要求的方法。
public var msg:String = ""; public function write(src){ msg += src; } public function flush(){ this.send(msg+"\r"); msg = ""; }
这样在fla里发送的方式就改为
conn.write("hello world"); conn.flush();
这样是不是又规范又符合Java的要求了呢?我只是举是一个简单例子,你可以按要求自己再修改。 1。4 AS3 与 Java 通信 Action Script 3 最后是传说中的as3了,这里我们用Socket中的writeUTFBytes();来写字符串。首先来看fla版的
var SERVER_PORT:Number = 10086; var SERVER_IP:String = "127.0.0.1"; var conn:Socket = new Socket(SERVER_IP,SERVER_PORT); conn.addEventListener("connect",socketConnect); conn.addEventListener("socketData",socketData); function socketConnect(event:Event){ event.target.writeUTFBytes("hello world"); event.target.writeByte(10); event.target.flush(); } function socketData(event:ProgressEvent){ trace(event.target.readUTFBytes(event.target.bytesAvailable)); }
看看这个fla版本的是不是在代码上思路更加清晰呢?所有事件已经全部改为监听的方式,并且所有事件将把事件作为参数传入函数。 bytesAvailable为字节长度,而readUTFBytes的参数是从当前指向的位置读取到参数位置,这样写就是读完。在as2里,如果在事件 触发的函数里写this指向的是触发事件的实例,而as3永远指向所在类的实力,触发事件的实例被记录在传入事件参数的target对象中。 as3更加注重的是oop,在fla里已经体现出来了。接下来就来看看DocmentClass的方法
package{class Run{ private var SERVER_PORT:Number = 10086; private var SERVER_IP:String = "127.0.0.1"; public function Run(){ //在这里写代码并在flash里设置该类为文档类,和直接写上帧上其实没有区别,入口函数 new ClientSocket(SERVER_IP,SERVER_PORT); } }}
当然还有一个ClientSocket.as的文件放这个socket客户端类
package { import flash.net.Socket; import flash.events.ProgressEvent; import flash.events.Event; import flash.events.IOErrorEvent; public class ClientSocket extends Socket { public function ClientSocket(ip:String,port:uint) { super(ip,port); addEventListener("cennect",socketConnect); addEventListener("socketData",socketData); addEventListener("ioError",ioError); } public function send(src:String) { writeUTFBytes(src); writeByte(10); flush(); } private function socketConnect(event:Event) { send("hello world"); } private function socketData(event:ProgressEvent) { trace(readUTFBytes(bytesAvailable)); } private function ioError(event:IOErrorEvent) { trace("connect error"); } } }
入口函数创建了一个客户端的对象,而具体的类的内部构造如上代码所示: 首先创建父类构造函数,再为自己添加监听,当连接时执行socketConnect();发送字符串,注意writeByte(10)是换行符。在as3 的socket类里还有其他的事件,这里因为教学原因所以没有过多的举例,相关可以查阅socket的帮助 close 在服务器关闭套接字连接时调度。 connect 在建立网络连接后调度。(这个监听在教程里已经实现) deactivate Flash Player 失去操作系统焦点并变为非活动状态时调度。 ioError 在出现输入/输出错误并导致发送或加载操作失败时调度。(以前是在onConnect传入false,而这里是直接引发ioError事件,更规范) securityError 若对 Socket.connect() 的调用尝试连接到调用方安全沙箱外部的服务器或端口号低于 1024 的端口,则进行调度。 socketData 在套接字接收到数据后调度。 (这个监听在教程里已经实现) 2 Java多线程服务器基本的通信做到以后就是修改代码增加功能了,这里我们必须让Java能支持多个线程的连接,这才是服务器呀。
import java.io.*; import java.net.*; public class Server extends ServerSocket{ //服务端口号常量(as要求必须大于1024,小于65535) private static final int SERVER_PORT = 10086; //构造函数 public Server() throws IOException{ super(SERVER_PORT); //监听新连接,为每个连接分配一个线程,将新的连接传入独立线程 Socket socket = accept(); new SocketThread(socket); } //入口函数... public static void main (String[] args) throws IOException{ new Server(); } //建一个类,该类属于独立的线程,他的每个实例都会在独立的线程里运行 class SocketThread extends Thread{ //申明流的空间在独立线程里了,因为他属于传送时所需,主线程只是监听有没有新连接 private Socket client; private BufferedReader in; private PrintWriter out; private String src; //构造函数 public SocketThread(Socket socket) throws IOException{ //初始客户端的连接为该线程传入的连接 client = socket; //初始流在进来后读取前,和写入后发送前所存放的空间 in = new BufferedReader(new InputStreamReader(client.getInputStream())); out = new PrintWriter(client.getOutputStream(),true); //准备工作完毕,启动该线程 start(); } public void run(){try { //循环等待读取信息 while(true){ //读取行信息,注意是以换行符结束的 src = in.readLine(); //如果发送"close",就跳出循环(断开连接) if(src.equals("close")){ break; } //在收到的信息前加是标识并发回(注意结尾加"\0",这是as的XMLSocket读入每条信息的条件.as3的Socket不需要) out.println("rev: "+src+"\0"); //以上out.println("xx")相当于out.write("xx");out.flush();的执行效果 System.out.println("msg is "+src) } //关闭连接 close(); }catch(IOException e){ }catch(NullPointerException e){ System.out.println("client closed"); }} } }
修改后的Java主线程监听是否有新的连接,如果有就把这个连接分配到新的线程,让他去监听消息,而自己继续监听连接,这样的思路是不是很清晰呢? 仔细看看其实不是很难,大部分的代码都和前面的一样,只是循环监听信息的代码被放到的独立的线程里面。关于多线程和一些Java的技术问题,为了对大家负 责,我依然谨慎言语,以免误导大家。现在你可以启动多个as对Java进行连接,并且他们之间互不干扰。一个线程对应一个连接,底层的工作非常透明,管理 非常容易。 3 AS 通过Java数据转发实现P2P通信谈到这里,其实要实现这步就非常容易了,原理上只要将本来Java收到后返回的信息,发到别人这里去,就可以了。原理 如下所示 flash_1 -> Java -> flash_2 flash_2 -> Java -> flash_3 flash_3 -> Java -> flash_1 这样任何两个flash之间都能通过java转发了,现在只有一个问题,就是Java怎么知道我的信息要发给谁?其实很简单我们在每个连接连入的时候发送 一条注册信息,让Java知道我的名字,而别人只要在字符串前加上我的名字就可以了。那么在Java里 我们需要两个功能 1个是增加和删除自己的标识 2是识别字符串中哪些是名字,哪些是信息这里我们用到方法是<空格> "r s1";这样的一条信息过去,Java服务器要处理为该连接添加一个标识s1,而在这以后任何客户端只要发送 "s1 Hello";就会把"Hello"这个字符串发送给标识为s1的客户端,这样两个flash之间就完全实现了数据互通 "u s1";当离开的时候可以用这个代码来删除s1的标识符为了简单和安全,我们可以暂设为标识必须是两位,以字母开头,这样的组合已经超过千种,绝对够用 了。这样只要判断空个所出现的位置即可,如果是第二位就是注册或卸载标识,如果是第三位就是字符转发了,如果都没有,那就是错误信息。把上面的Run里的 out.println("rev: "+src+"\0");改成以下信息就可以判断信息是注册还是卸载了
//屏蔽所有长度小于4的信息,不做处理. if(line.length()<4){ out.write("error: length<4"); out.flush(); line = in.readLine(); continue; } //命令字符 if (line.charAt(1)==' '){ //相应客户端命令请求 name = line.substring(2); switch (line.charAt(0)) { case 'r': //注册客户端 if (!registered && name.length()==2){ //为自己加一个ID Server.clientID.put(name,client); registered = true; //返回注册成功 out.write("registeration successed"); out.flush(); } break; case 'u': //删除客户端 Server.clientID.remove(name); registered = false; break; } }else if (line.charAt(2)==' '){ //这里是转发代码; }
当然这里用的一些API在前面还要声明过。在线程类里增加两条申明
private String name; private boolean registered;
构造函数里
registered = false;
当然最重要的是还要在Server的主线程里声明一个放ID的容器
public static HashMap clientID = new HashMap();
这样每个连接都有自己的ID了 现在要做的是在转发了,在上面的转发代码的地方写
send(line.substring(0,2),line.substring(3));
当然send函数还没有定义呢,现在定义
public boolean send(String id, String src) throws IOException { //读取标识的地址 Socket socket = (Socket)Server.clientID.get(id); if (socket != null){ out = new PrintWriter(socket.getOutputStream(), true); out.write(src); out.flush(); return true; }else{ return false; } }
这里我加入了判断id是否存在,当不存在就没有任何操作,并且将操作结果成功与否返回,在send的时候就可以分类成功或不成功分别做什么了。 马上来开两个AS吧,用到我们刚才第一章节里自己封装的as2,把加载成功的地方改成send("r c1\r");和send("r c2\r"); Action Script 2
//file1 var SERVER_PORT:Number = 10086; var SERVER_IP:String = "127.0.0.1"; conn:Socket = new Socket(); conn.connect(SERVER_IP,SERVER_PORT); conn.onConnect = function (success:Boolean){ if (success){ write("r c1"); flush(); } } //file2 var SERVER_PORT:Number = 10086; var SERVER_IP:String = "127.0.0.1"; conn:Socket = new Socket(); conn.connect(SERVER_IP,SERVER_PORT); conn.onConnect = function (success:Boolean){ if (success){ write("c2 hello"); flush(); } }
依次运行file1,file2看看,file2运行的时候是不是成功收到了一个hello呢?嘿嘿。这样做虽然底层还是没有实现P2P,但是效果已经达到,如果还是觉得不够理想,那么可以每个客户端都绑定一个Java的ServerSocket,负责收信息,并转发给同绑定Flash,这样虽然没有实现swf的p2p,但是在底层已经p2p了。 [完毕... 答疑和下载 在11楼] <1 AS与Java最基本的通信> .. OK <2 Java多线程服务器> .. OK <3 AS 通过Java数据转发实现P2P通信> .. OK <4 将P2P方式用类封装资源免费下载> .. OK AS.Socket.P2P.rar (7.06 KB)
Word教程网 | Excel教程网 | Dreamweaver教程网 | Fireworks教程网 | PPT教程网 | FLASH教程网 | PS教程网 |
HTML教程网 | DIV CSS教程网 | FLASH AS教程网 | ACCESS教程网 | SQL SERVER教程网 | C语言教程网 | JAVASCRIPT教程网 |
ASP教程网 | ASP.NET教程网 | CorelDraw教程网 |