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
  1. public class SocketUtil {
  2. /**
  3. * 创建ServerSocket
  4. * @param port
  5. * @return
  6. */
  7. public static ServerSocket getServerSocket(int port){
  8. ServerSocket server = null;
  9. try {
  10. server = new ServerSocket(port);
  11. System.out.println("------ServerSocket创建成功,Port:"+port);
  12. return server;
  13. } catch (IOException e) {
  14. if(server!=null && !server.isClosed()){
  15. try {
  16. server.close();
  17. } catch (IOException e1) {
  18. e1.printStackTrace();
  19. }
  20. }
  21. throw new RuntimeException("创建ServerSocket时发生异常,Port:"+port,e);
  22. }
  23. }
  24. /**
  25. * 获取Socket
  26. * @param server
  27. * @return
  28. */
  29. public static Socket getSocket(ServerSocket server){
  30. Socket socket = null;
  31. try {
  32. socket = server.accept();
  33. System.out.println("------Socket连接成功,IP:"+socket.getInetAddress());
  34. return socket;
  35. } catch (IOException e) {
  36. if(socket!=null && !socket.isClosed()){
  37. try {
  38. socket.close();
  39. } catch (IOException e1) {
  40. e1.printStackTrace();
  41. }
  42. }
  43. throw new RuntimeException("创建Socket时发送异常",e);
  44. }
  45. }
  46. }
然后创建一个带多线程的类,用于服务器与客户端的IO通信
  1. public class SocketThread implements Runnable {
  2. private Socket socket;
  3. private String encoding;
  4. public SocketThread(Socket socket,String encoding) {
  5. this.socket = socket;
  6. this.encoding = encoding;
  7. }
  8. /**
  9. * 与客户端交互代码
  10. */
  11. @Override
  12. public void run() {
  13. try {
  14. BufferedReader br = new BufferedReader(new InputStreamReader(socket
  15. .getInputStream(), encoding));
  16. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
  17. socket.getOutputStream(), encoding));
  18. String getMsg;
  19. while ((getMsg = br.readLine()) != null && !"exit".equalsIgnoreCase(getMsg)) {
  20. // 客户端未提出"exit"命令,则循环交流
  21. System.out.println("From client message:" + getMsg);
  22. bw.append("你好[" + socket.getInetAddress() + "],服务器收到你的信息:"
  23. + getMsg + "\r\n");
  24. bw.flush();
  25. }
  26. //客户端提出"exit"请求,关闭当前socket...
  27. br.close();
  28. bw.close();
  29. socket.close();
  30. System.out.println("当前Socket连接结束......");
  31. } catch (Exception e) {
  32. if(!socket.isClosed()){
  33. try {
  34. socket.close();
  35. } catch (IOException e1) {
  36. e1.printStackTrace();
  37. }
  38. }
  39. throw new RuntimeException("Socket线程类发送异常...",e);
  40. }
  41. }
  42. }
最后在Main函数中启动Socket服务即可:
  1. public static void main(String[] args) {
  2. new SocketServer().startSocket();
  3. }
 
  • Flex客户端代码
Flex端创建Socket有两种方式:
第一种通过connect方法连接Socket服务器:
  1. var socket:Socket = new Socket();
  2. socket.connect("localhost",);

第二种通过创建Socket实例时在构造函数中传入服务器ip和端口号连接:

  1. socket = );
 Flex通过ByteArray传送IO数据,这里有一点稍微注意一下在写入的内容后面会加"\r\n"回车换行符,因为java端是通过BufferedReader.readLine的形式获取一行数据,如果不换行服务器端IO就一直处于阻塞状态:
  1. //ByteArray存放数据
  2. var message:ByteArray = new ByteArray();
  3. //使用UTF形式防止中文乱码
  4. message.writeUTFBytes(txt_socket.text+"\r\n");
  5. //数据写入缓冲区
  6. socket.writeBytes(message);
 Flex有多种事件用于监听Socket的状态:
  1. Event.CONNECT:Socket与服务器成功连接时触发的事件
  2. Event.CLOSE:Socket与服务器断开连接时触发的事件
  3. IOErrorEvent.IO_ERROR:Socket通信时发生IO错误时触发的事件
  4. ProgressEvent.SOCKET_DATA:服务器返回数据时触发的事件
 
新建一个Flex普通项目,入口文件定义为index.mxml,在mxml文件中新建一个textinput文本框用于获取用户输入的内容,button按钮用户发送内容到java socket服务器,一个label用户显示向前socket状态,另一个label用于显示从服务器返回的信息。 index.mxml代码如下:
  1. <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  2. xmlns:s="library://ns.adobe.com/flex/spark"
  3. xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
  4. <fx:Script>
  5. <![CDATA[
  6. private var socket:Socket = null;
  7. protected function button1_clickHandler(event:MouseEvent):void
  8. {
  9. if(socket==null || !socket.connected){
  10. //连接服务器(ip,port)
  11. socket = new Socket("localhost",10086);
  12. //成功连接状态事件
  13. socket.addEventListener(Event.CONNECT,function connFun(e:Event):void{
  14. l_status.text = "Connect to server success...";
  15. });
  16. //连接中断事件
  17. socket.addEventListener(Event.CLOSE,function closeFun(e:Event):void{
  18. l_status.text = "Connect to server closed...";
  19. });
  20. //连接异常事件
  21. socket.addEventListener(IOErrorEvent.IO_ERROR,function closeFun(e:IOErrorEvent):void{
  22. l_status.text = "Connect exception ..."+e.toString();
  23. });
  24. //服务器信息事件
  25. socket.addEventListener(ProgressEvent.SOCKET_DATA,function dataFun(e:ProgressEvent):void{
  26. var getMsg:ByteArray = new ByteArray;
  27. socket.readBytes(getMsg);
  28. l_result.text = getMsg.toString();
  29. });
  30. }
  31. //ByteArray存放数据
  32. var message:ByteArray = new ByteArray();
  33. //使用UTF形式防止中文乱码
  34. message.writeUTFBytes(txt_socket.text+"\r\n");
  35. //数据写入缓冲区
  36. socket.writeBytes(message);
  37. //将缓冲区数据发送出去
  38. socket.flush();
  39. //清空文本框内容
  40. txt_socket.text = "";
  41. }
  42. ]]>
  43. </fx:Script>
  44. <fx:Declarations>
  45. <!-- 将非可视元素(例如服务、值对象)放在此处 -->
  46. </fx:Declarations>
  47. <s:Button x="156" y="56" label="按钮" click="button1_clickHandler(event)"/>
  48. <s:TextInput x="20" y="56" id="txt_socket"/>
  49. <s:Label x="20" y="104" id="l_status"/>
  50. <s:Label x="234" y="65" id="l_result"/>
  51. </s:Application>
代码编写完成后运行index.mxml文件,最后执行效果就如前面【实例效果】所示。
 
 
  • 安全沙箱
下面这段是从网上抄的:
----------------------------------------------------------------------------
在 Adobe Flash Player 升级到 9.0.124 后,由于安全策略更改,原来 Socket 或 XmlSocket 的应用里的 http 方式加载安全策略的手段不能继续使用。更改如下:
1, 首先检测目标服务器的 843 端口是否提供安全策略 
2, 如果 1 没有检测到策略,则检测 actionscript 是否使用了 Security.loadPolicyFile(xmlsocket://)手段提供安全策略,如果还没检测到,则使用第 3 步检测
3, 检测目标服务器目标端口是否提供安全策略。
在说具体处理方式前,我先描述一下 Flash Player 的验证过程。在 Flex 程序发出 Socket 或 XmlSocket( 以下统称为 Socket) 请求前, FlashPlayer 会先判断是否为本地调用,如果不是。即用一个 Socket 去链接到你的服务端,三次握手成功后一方面发出字符串“ <policy-file-request/>\0 “另一方面监听返回的安全策略。安全策略接收成功后, FlashPlayer 就断开验证的 Socket ,然后再运行程序本身的 Socket 。在整个 SWF 运行期间,无论你请求多少次,只要域相同, FlashPlayer 就只验证一次。这里有两个重点: 
第一个是验证的 Socket 和程序的 Socket 是两个 Socket 。所以你在本地测试时,服务端监听到 N 个 Socket 请求,但布置到服务端后,服务端会监听到 N+1 个请求。
第二是验证的 Socket 发送“ <policy-file-request/>\0 “请求和接收你的策略文件是没有先后关系的,所以你没必要接收完“ <policy-file-request/>\0 “后才发策略文件。我的做法是只要监听到请求,就把策略字符串发过去。
-----------------------------------------------------------------------------------
 
那么简单的说,如果Flex项目依赖其它语言的服务器的话(比如依赖J2EE服务器),在flex的socket客户端向JavaSocket服务器发送请求之前,Flex会优先发送一个安全验证消息,如果java服务器不返回验证消息则当前socket通信失败。
解决办法有很多种,我在网上也看了很多,但是很多写得有问题。
根据我多方调查,个人觉得这种方案比较靠谱:
在Java服务器端创建一个端口号为843的ServerSocket监听Flex安全沙箱验证消息,如果接收到<policy-file-request/>文件信息,则向客户端返回XMl验证内容:“<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0”
具体代码如下:
  1. /**
  2. * 处理与Flex认证的线程类
  3. * @author Administrator
  4. */
  5. public class PolicyThread implements Runnable {
  6. private final String policy_xml = "<policy-file-request/>";
  7. private final String cross_xml = "<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0";
  8. private Socket socket;
  9. public PolicyThread(Socket socket){
  10. this.socket = socket;
  11. }
  12. @Override
  13. public void run() {
  14. try {
  15. //接收并发送Flex安全验证请求
  16. BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  17. PrintWriter pw = new PrintWriter(socket.getOutputStream());
  18. ];
  19. br.read(by, , );
  20. String s = new String(by);
  21. if(s.equals(policy_xml)){
  22. System.out.println("接收policy-file-request认证");
  23. pw.print(cross_xml);
  24. pw.flush();
  25. br.close();
  26. pw.close();
  27. socket.close();
  28. System.out.println("完成policy-file-request认证");
  29. }
  30. } catch (IOException e) {
  31. if(!socket.isClosed()){
  32. try {
  33. socket.close();
  34. } catch (IOException e1) {
  35. e1.printStackTrace();
  36. }
  37. }
  38. throw new RuntimeException("执行policy认证时发生异常",e);
  39. }
  40. }
  41. }
  1. public class PolicyServer implements Runnable{
  2. ;
  3. private boolean status = true;
  4. private ServerSocket server = null;
  5. @Override
  6. public void run() {
  7. //创建安全验证服务器
  8. server = SocketUtil.getServerSocket(policy_port);
  9. while(status){
  10. Socket socket = SocketUtil.getSocket(server);
  11. new Thread(new PolicyThread(socket)).start();
  12. }
  13. }
  14. /**
  15. * 启动服务器
  16. */
  17. public void startPolicy(){
  18. new Thread(this).start();
  19. }
  20. /**
  21. * 关闭服务器
  22. */
  23. public void stopPolicy(){
  24. status = false;
  25. if(server!=null && !server.isClosed()){
  26. try {
  27. server.close();
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }
Flex客户端向Java发送第一次Socket请求(例子里的端口号是10086)时,ServerSocket843端口会收到安全沙箱验证,随后server将正确的验证消息返回给Flex客户端,Flex认证成功后真正的10086端口Socket连结就已经搭建了,随后双方就可以畅通无阻通信了(一次会话只进行一次沙箱验证)。
 
 
  • Servlet启动ServerSocket
我通常比较喜欢创建一个servlet,在web.xml中配置容器启动时运行servlet的init方法,这样端口号为10086和843的serverSocket就会启动:
  1. public class InitServers extends HttpServlet {
  2. private static final long serialVersionUID = 1L;
  3. /**
  4. * @see HttpServlet#HttpServlet()
  5. */
  6. public InitServers() {
  7. super();
  8. }
  9. /**
  10. * @see Servlet#init(ServletConfig)
  11. */
  12. public void init(ServletConfig config) throws ServletException {
  13. new PolicyServer().startPolicy();
  14. new SocketServer().startSocket();
  15. }
  16. /**
  17. * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
  18. */
  19. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  20. // TODO Auto-generated method stub
  21. }
  22. /**
  23. * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
  24. */
  25. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  26. // TODO Auto-generated method stub
  27. }
  28. }
 web.xml
 
  1. <servlet>
  2. <display-name>InitServers</display-name>
  3. <servlet-name>InitServers</servlet-name>
  4. <servlet-class>socket.InitServers</servlet-class>
  5. <load-on-startup>1</load-on-startup>
  6. </servlet>
 
以上一个完整的Flex+Java的Socket通信就完成了。

Flex通信-与Java实现Socket通信实例的更多相关文章

  1. Java的Socket通信简单实例

    服务端 package testlxd; import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...

  2. Java:Socket通信

    Socket通常也称作"套接字".用于描写叙述IP地址和port,是一个通信链的句柄.应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ServerS ...

  3. java的socket通信

    本文讲解如何用java实现网络通信,是一个非常简单的例子,我比较喜欢能够立马看到结果,所以先上代码再讲解具体细节. 服务端: import java.io.BufferedReader; import ...

  4. Java的Socket通信----通过 Socket 实现 TCP 编程之多线程demo(2)

    JAVA Socket简介 所谓socket 通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过”套接字”向网络发出请求或者应答网络请求. import java.io ...

  5. C++服务器与java进行socket通信案例

    分类: [java]2012-10-08 12:03 14539人阅读 评论(46) 收藏 举报 注:本代码版权所有!!!转载时请声明源地址:http://blog.csdn.net/nuptboyz ...

  6. java NIO socket 通信实例

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zhuyijian135757/article/details/37672151 java Nio 通 ...

  7. java的Socket通信例子及关于java.net.SocketException: Socket is closed错误

    今天写socket数据相互通信的时候,碰到一个及其蛋疼的错误.单向传输数据的时候server与client是没有问题的,但是两个都有输入输出操作的时候就出现了这个问题 java.net.SocketE ...

  8. Java实现Socket通信

    一对一通信: 服务器端: public class ServerDemo { public static void main(String[] args) { ServerSocket serverS ...

  9. JAVA ANDROID SOCKET通信检测(SERVER)连接是否断开

    Pre 解决思路 代码后记: 客户端app上的部分代码 调用: 服务器上: 客户端判断服务器是否还活着代码: PRE 在利用socket写通讯程序的时候,想检测服务器是否还活着. 从网上找了很多资料, ...

随机推荐

  1. SPOJ 1487 Query on a tree III(划分树)

    题目链接:http://www.spoj.com/problems/PT07J/ 题意:给出一个有根树,1为根节点,每个节点有权值.若干询问,询问以u为根的子树中权值第K小的节点编号. 思路:DFS一 ...

  2. Web Servers in Visual Studio for ASP.NET Web Projects

    https://msdn.microsoft.com/en-us/library/58wxa9w5(v=vs.120).aspx When you develop web projects in Vi ...

  3. Back to Back Order Process

    Steps involved involved in back to back order process in oracle apps 1. Enter Sales Order 2. Book Sa ...

  4. JavaScript高级程序设计之数据类型

    首先讲讲关于js文件放置的问题,如果把<script>放在head标签处,浏览器会先加载完该处的所有不使用defer属性的js文件再呈现页面的内容(浏览器在遇到body标签时才呈现内容), ...

  5. CAS 在 Tomcat 中实现单点登录

    单点登录(Single Sign On , 简称 SSO )是目前比较流行的服务于企业业务整合的解决方案之一, SSO 使得在多个应用系统 中,用户只需要登录一次就可以访问所有相互信任的应用系统.CA ...

  6. POJ 2689

    题意:求[l, r]区间中的间隔距离最大与最小的相邻两个素数,r<2200000000, r-l<10^6 题解: 对于<a的合数,其必然存在一个素因子b<=sqrt(a). ...

  7. innodb锁之间的兼容性判断

    检查锁与锁之间的兼容性 路径:/mysql-5.5.43/storage/innobase/lock/lock0lock.c 实现:见锁的强度比较  row 可理解为 lock 的锁模式  colum ...

  8. 51nod1349 最大值

    还是傻叉单调栈 #include<cstdio> #include<cstring> #include<cctype> #include<algorithm& ...

  9. volley(5) 参数total_remain:totalqty, data:[{ bar_status:XX , bar_code: "XX",bar_remain:XX, bar_whcode:"XX" , bar_prodcode:"XX",bar_id:XX,bar_location: "XX", pr_detail: "XX" , bar_batchcode:method:POST

    1. 来源  : WHCombineBatchFragment.java 2. 部分代码 WHCombineBatchFragmentCombineBtnClickEvent whc2;private ...

  10. [Swift系列]003- 函数

    [基础] Swift函数格式: 1.定义格式: func   函数名(参数名1:数据类型,... ,参数名n:数据类型) -> (返回值类型1,...,返回值类型n){ ///函数体内语句 } ...