Flex通信-与Java实现Socket通信实例 转自:http://blessht.iteye.com/blog/1136888
博客分类:
- 环境准备
【服务器端】
JDK1.6,“java.net”包对网络编程提供了非常全面的支持,包括Socket
开发环境:Eclipse
【客户端】
Flex4,”flash.net”包也提供了Socket的支持
开发环境:FlashBuilder4
- 实例效果
我是用Java启动一个ServerSocket作为服务器,Flex创建一个页面,当点击页面上的按钮时向Java服务器发送消息。
Flex客户端输入“阿里巴巴”再点击按钮:
Java控制台:
- 注意事项
Flex项目分为两种:一种是普通的本地项目,也就是不依赖其它服务器;另一种是远程服务器项目,这需要依赖其它语言的服务器容器。如果是普通的本地项目,Socket通信是非常容易的,但是如果是远程项目,Socket通信需要考虑Flex安全沙箱问题,后面会详细介绍。
- Java Socket服务器
编写Socket Server代码的步骤通常是:
①创建ServerSocket,定义服务端口号
②使用ServerSocket.accept()监听socket请求,如果有请求会创建一个Socket对象
③通过socket.getInputStream()获取客户端的请求数据
④通过socket.getOutputStream()向客户端返回数据
⑤通过socket.close()结束本次会话
按照上面的步骤,如果有多个客户端向服务器发送请求的话,服务器只会处理第一个请求,其它请求会排队等待,只有第一个请求执行socket.close的时候下一个客户端请求才会运行。为了实现多客户端并发请求,在第②步后面需要建立多线程。
废话不多说,直接代码说明。
首先创建一个SocketUtil类,用于创建ServerSocket和获取Socket
- public class SocketUtil {
- /**
- * 创建ServerSocket
- * @param port
- * @return
- */
- public static ServerSocket getServerSocket(int port){
- ServerSocket server = null;
- try {
- server = new ServerSocket(port);
- System.out.println("------ServerSocket创建成功,Port:"+port);
- return server;
- } catch (IOException e) {
- if(server!=null && !server.isClosed()){
- try {
- server.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- throw new RuntimeException("创建ServerSocket时发生异常,Port:"+port,e);
- }
- }
- /**
- * 获取Socket
- * @param server
- * @return
- */
- public static Socket getSocket(ServerSocket server){
- Socket socket = null;
- try {
- socket = server.accept();
- System.out.println("------Socket连接成功,IP:"+socket.getInetAddress());
- return socket;
- } catch (IOException e) {
- if(socket!=null && !socket.isClosed()){
- try {
- socket.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- throw new RuntimeException("创建Socket时发送异常",e);
- }
- }
- }
然后创建一个带多线程的类,用于服务器与客户端的IO通信
- public class SocketThread implements Runnable {
- private Socket socket;
- private String encoding;
- public SocketThread(Socket socket,String encoding) {
- this.socket = socket;
- this.encoding = encoding;
- }
- /**
- * 与客户端交互代码
- */
- @Override
- public void run() {
- try {
- BufferedReader br = new BufferedReader(new InputStreamReader(socket
- .getInputStream(), encoding));
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
- socket.getOutputStream(), encoding));
- String getMsg;
- while ((getMsg = br.readLine()) != null && !"exit".equalsIgnoreCase(getMsg)) {
- // 客户端未提出"exit"命令,则循环交流
- System.out.println("From client message:" + getMsg);
- bw.append("你好[" + socket.getInetAddress() + "],服务器收到你的信息:"
- + getMsg + " ");
- bw.flush();
- }
- //客户端提出"exit"请求,关闭当前socket...
- br.close();
- bw.close();
- socket.close();
- System.out.println("当前Socket连接结束......");
- } catch (Exception e) {
- if(!socket.isClosed()){
- try {
- socket.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- throw new RuntimeException("Socket线程类发送异常...",e);
- }
- }
- }
最后在Main函数中启动Socket服务即可:
- public static void main(String[] args) {
- new SocketServer().startSocket();
- }
- Flex客户端代码
Flex端创建Socket有两种方式:
第一种通过connect方法连接Socket服务器:
- var socket:Socket = new Socket();
- socket.connect("localhost",10086);
- socket = new Socket("localhost",10086);
Flex通过ByteArray传送IO数据,这里有一点稍微注意一下在写入的内容后面会加"
"回车换行符,因为java端是通过BufferedReader.readLine的形式获取一行数据,如果不换行服务器端IO就一直处于阻塞状态:
- //ByteArray存放数据
- var message:ByteArray = new ByteArray();
- //使用UTF形式防止中文乱码
- message.writeUTFBytes(txt_socket.text+" ");
- //数据写入缓冲区
- socket.writeBytes(message);
Flex有多种事件用于监听Socket的状态:
- Event.CONNECT:Socket与服务器成功连接时触发的事件
- Event.CLOSE:Socket与服务器断开连接时触发的事件
- IOErrorEvent.IO_ERROR:Socket通信时发生IO错误时触发的事件
- ProgressEvent.SOCKET_DATA:服务器返回数据时触发的事件
新建一个Flex普通项目,入口文件定义为index.mxml,在mxml文件中新建一个textinput文本框用于获取用户输入的内容,button按钮用户发送内容到java socket服务器,一个label用户显示向前socket状态,另一个label用于显示从服务器返回的信息。 index.mxml代码如下:
- <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">
- <fx:Script>
- <![CDATA[
- private var socket:Socket = null;
- protected function button1_clickHandler(event:MouseEvent):void
- {
- if(socket==null || !socket.connected){
- //连接服务器(ip,port)
- socket = new Socket("localhost",10086);
- //成功连接状态事件
- socket.addEventListener(Event.CONNECT,function connFun(e:Event):void{
- l_status.text = "Connect to server success...";
- });
- //连接中断事件
- socket.addEventListener(Event.CLOSE,function closeFun(e:Event):void{
- l_status.text = "Connect to server closed...";
- });
- //连接异常事件
- socket.addEventListener(IOErrorEvent.IO_ERROR,function closeFun(e:IOErrorEvent):void{
- l_status.text = "Connect exception ..."+e.toString();
- });
- //服务器信息事件
- socket.addEventListener(ProgressEvent.SOCKET_DATA,function dataFun(e:ProgressEvent):void{
- var getMsg:ByteArray = new ByteArray;
- socket.readBytes(getMsg);
- l_result.text = getMsg.toString();
- });
- }
- //ByteArray存放数据
- var message:ByteArray = new ByteArray();
- //使用UTF形式防止中文乱码
- message.writeUTFBytes(txt_socket.text+" ");
- //数据写入缓冲区
- socket.writeBytes(message);
- //将缓冲区数据发送出去
- socket.flush();
- //清空文本框内容
- txt_socket.text = "";
- }
- ]]>
- </fx:Script>
- <fx:Declarations>
- <!-- 将非可视元素(例如服务、值对象)放在此处 -->
- </fx:Declarations>
- <s:Button x="156" y="56" label="按钮" click="button1_clickHandler(event)"/>
- <s:TextInput x="20" y="56" id="txt_socket"/>
- <s:Label x="20" y="104" id="l_status"/>
- <s:Label x="234" y="65" id="l_result"/>
- </s:Application>
代码编写完成后运行index.mxml文件,最后执行效果就如前面【实例效果】所示。
- 安全沙箱
下面这段是从网上抄的:
----------------------------------------------------------------------------
在 Adobe Flash Player 升级到 9.0.124 后,由于安全策略更改,原来 Socket 或 XmlSocket 的应用里的 http 方式加载安全策略的手段不能继续使用。更改如下:
1, 首先检测目标服务器的 843 端口是否提供安全策略
2, 如果 1 没有检测到策略,则检测 actionscript 是否使用了 Security.loadPolicyFile(xmlsocket://)手段提供安全策略,如果还没检测到,则使用第 3 步检测
3, 检测目标服务器目标端口是否提供安全策略。
1, 首先检测目标服务器的 843 端口是否提供安全策略
2, 如果 1 没有检测到策略,则检测 actionscript 是否使用了 Security.loadPolicyFile(xmlsocket://)手段提供安全策略,如果还没检测到,则使用第 3 步检测
3, 检测目标服务器目标端口是否提供安全策略。
在说具体处理方式前,我先描述一下 Flash Player 的验证过程。在 Flex 程序发出 Socket 或 XmlSocket( 以下统称为 Socket) 请求前, FlashPlayer 会先判断是否为本地调用,如果不是。即用一个 Socket 去链接到你的服务端,三次握手成功后一方面发出字符串“ <policy-file-request/>