`
cx732cx
  • 浏览: 18695 次
社区版块
存档分类
最新评论

Flex socket通信实践学习笔记(2)-1

 
阅读更多

Flex socket通信实践学习笔记(2)-1
2011年04月17日
  面,阿堂和朋友们简单聊了一下,给出了一些FLEX和JAVA交互的操作图的界面一文(见 Flex socket通信实践学习笔记(1)),见阿堂的新浪空间(http://blog.sina.com.cn/s/blog_4c925dca0100s38p.ht ml),由于阿堂平常一直比较忙,所以代码没有粘出来,今天我就给出该操作图相应的后台服务端java代码和客户端的FLEX代码.对于flex和JAVA的交互,我这里也简单总结一下,谈一下自己的看法!
  1.flex和java交互时,需要三次握手过程,握手成功后,flex客户端会检测通信端口中是否存在安全策略文件,此时客户端发送以下报文内容.
  

  
服务端在收到该报文后,应该向客户端发送安全策略文件。
  //Flex 安全策略文件
  String xml ="";
  xml = xml+"";
  xml = xml+"";
  xml = xml+"";
  之后再进行正常Socket通信.
  所以,朋友们会在阿堂后面粘出来的代码中看到有如下代码
  if(head.equals("")){
  pw.print(xml+"\0");
  pw.flush();
  }else{
  ...
  }
  代码的判断,对于安全策略文件,不是阿堂这篇文章讨论的重点,所以我就不再详细说明了。有兴趣的朋友可以继续看flex安全策略文件方面的介绍和说明,网上有很多这方面的介绍
   2.flex和java交互中需要约定socket方面的通信协议或者说是rule.注意,这个是相对于开发的项目或游戏本身约定的通信协议,也就是说对于开发某个游戏,双方需要实际交互过程中,来议定的一些规则.如下面简单的网络聊天室,就议定了五类规则,0表示登录信息,1表示普通信息,2表示客户端总人数,3表示离开信息,4表示用户列表信息. (当然,我们用BlazeDS,apache mina等框架开发较为大中型的flash游戏时,我们议定的规则会比下述规则复杂得多.象我们部门其它项目组,开发的“德州扑克”,用的apache mina和flex交互时,就议定了2m-30种协议规则,每种规则传递的不是简单的数字,而是更为丰富的Array数组。java端是传递的JSon格式到flex客户端,flex端传递给java端是Array数组)但是,不管传递的数据有多复杂或者用什么框架,如BlazeDS,apache mina,FMS,Red5等,Flex和Java交互的基本原理都是一样的,只不过,用这些框架时,我们对于Socket的框架少了一些操作而也,很多的对于Socket框架方面的底层封装少了很多的操作,大大方便了Flex和服务端的交互.
  
(1)java后台服务端
  //用户登录消息头
  public static final String LOGIN_HEAD = "0";
  //发送普通消息头
  public static final String MESSAGE_HEAD = "1";
  //客户端人数消息头
  public static final String CLIENT_NUM_HEAD = "2";
  //客户端离开消息头
  public static final String LOGIN_OUT_HEAD  = "3";
  //用户列表消息头
  public static final String USER_LIST  = "4";
  (2)flex客户端
  // 用户登录消息头
  public  static const LOGIN_HEAD:String = "0";
  // 发送普通消息头
  public  static const MESSAGE_HEAD:String = "1";
  // 客户端人数消息头
  public  static const CLIENT_NUM_HEAD:String = "2";
  // 客户端离开消息头
  public static const  LOGIN_OUT_HEAD:String= "3";
  //如果是用户列表消息头
  public static const USER_LIST:String = "4";
  (3)Java服务端,主要用了三个类:一个主程序启动类启动监听服务MainServer.java,Socket线程处理类处理与每一个客户端的通信
  SocketThread.java,广播类BroadCaster.java广我们的消息给所有的客户端。这实际上比较典型的设计模式--观察者设计模式。
  (4)Flex客户端 logWin.mxml,SocketExample.mxml
  服务端代码如下
  
代码如下
  package com.chat.demo;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.PrintWriter;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.net.SocketAddress;     public class MainServer {  //监听端口
  private static  final int SERVER_PORT = 9999;
  //服务器
  private ServerSocket server;
  //广播者
  private BroadCaster broadCaster = new BroadCaster();
  public MainServer(){
  }
  public void startServer(){
  //Flex 安全策略文件
  String xml ="";
  xml = xml+"";
  xml = xml+"";
  xml = xml+"";
  try{
  //创建server端口 9999
  server = new ServerSocket(SERVER_PORT);
  System.out.println("---服务端启动成功 ! 监听端口:"+SERVER_PORT);
  System.out.println("---等待客户端连接");
  while(true){
  //获得客户端连接socket
  Socket socket = server.accept();
  System.out.println("----客户端已连接:"+socket.getRemoteSocketAddress());
  //Flash socket跨域访问设置
  BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-
  8"));
  PrintWriter pw = new PrintWriter(socket.getOutputStream());
  //接收用户名
  char[] by = new char[22];
  br.read(by,0,22);
  String head = new String(by);
  if(head.equals("")){
  pw.print(xml+"\0");
  pw.flush();
  }else{
  //截取第一个字符串,判断消息类型
  String cmd = head.substring(0, 1);
  if(BroadCaster.LOGIN_HEAD.equals(cmd)){
  //如果接收的是登录信息
  String userName = head.substring(1, head.indexOf('\n'));
  System.out.println(userName+" 上线了! ");
  //将socket添加到广播对象 Vector中
  broadCaster.add(socket);
  //创建Scoket线程与客户端通信
  SocketThread thread = new SocketThread(broadCaster,socket,userName);
  //启动线程
  thread.start();
  //发送在线人数信息到客户端
  broadCaster.sendClientNumToAll();
  //发送登录信息给所有客户端
  broadCaster.sendLoginInfoToAll(userName);
  //将用户名添加到用户列表中
  broadCaster.addUserName(userName);
  //发送所有用户名列表,给所有客户端
  broadCaster.sendUserListToAll();  }  }  }  }catch(IOException e){  e.printStackTrace();  }  }     public static void main(String[] args){  //启动Socket服务器
  MainServer mainServer = new MainServer();
  mainServer.startServer();
  }
  }
  package com.chat.demo;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.net.Socket;
  public class SocketThread extends Thread {
  //保存广播引用
  private BroadCaster broadCaster;
  //用户名
  private String userName;
  //保存套接字引用
  private Socket socket;
  //套接字输入流
  private BufferedReader br;
  public SocketThread(BroadCaster broadCaster,Socket socket,String userName){
  this.broadCaster = broadCaster;
  this.socket = socket;
  this.userName = userName;
  }
  public void run(){
  try{
  if(socket !=null && !socket.isClosed()){
  //获取客户端发送过来的信息
  br = new BufferedReader(new InputStreamReader(this.socket.getInputStream(),"UT F-8"));
  //消息原始内容
  String msg = null;
  //消息头
  String head = null;
  //消息主体
  String msgBody = null;
  //发送的消息内容
  String sendMsg = null;
  while((msg = br.readLine()) != null){
  head = msg.substring(0, 1);
  msgBody = msg.substring(1);
  if(BroadCaster.LOGIN_HEAD.equals(head)){
  //如果是登录信息
  sendMsg = msgBody+"登录了";
  System.out.println(sendMsg);
  //发送在线人数信息到客户端
  broadCaster.sendClientNumToAll();
  //用户登录消息,则发送用户登录消息到所有客户端
  broadCaster.sendLoginInfoToAll(msgBody);
  //发送所有用户列表给所有客户端
  broadCaster.addUserName(msgBody);
  //发送用户信息列表给所有客户端
  broadCaster.sendUserListToAll();
  }else if(BroadCaster.MESSAGE_HEAD.equals(head)){
  System.out.println(msgBody);
  //如果接收的是普通信息,则发送该消息到所有的客户端
  broadCaster.sendMessageToAll(msgBody);  }  }  }  else{  System.out.println("---------连接已经关闭--------------");
  }
  }catch(Exception e){
  }finally{
  try{
  //客户端离开了,移除广播者对象中的Socket
  broadCaster.remove(socket);
  //关闭输入流
  if(br != null){
  br.close();
  }
  //关闭Socket连接,释放资源
  if(socket != null){
  socket.close();
  }
  br = null;
  socket = null;
  System.out.println("客户端离开");
  //发送当前在线人数消息给所有的客户端
  broadCaster.sendClientNumToAll();
  //移出用户登录名称
  broadCaster.removeUserName(userName);
  //发送用户离开消息给每一个客户端
  broadCaster.sendLoginOutInfoToAll(userName);
  //发送在线用户信息列表消息给所有客户端
  broadCaster.sendUserListToAll();
  }catch(IOException e){
  }
  }
  }
  }
  package com.chat.demo;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.net.Socket;
  import java.util.Vector;
  public class BroadCaster {
  //用户登录消息头
  public static final String LOGIN_HEAD = "0";
  //发送普通消息头
  public static final String MESSAGE_HEAD = "1";
  //客户端人数消息头
  public static final String CLIENT_NUM_HEAD = "2";
  //客户端离开消息头
  public static final String LOGIN_OUT_HEAD  = "3";
  //用户列表消息头
  public static final String USER_LIST  = "4";
  //Socket 客户端连接用户名
  private Vector userNameVector = new Vector();
  //Scoket 客户端连接Vector
  private Vector socketVector = new Vector();
  public Vector getSocketVector() {
  return socketVector;
  }
  public void setSocketVector(Vector socketVector) {
  this.socketVector = socketVector;  }     //添加用户名
  public void addUserName(String userName){
  this.userNameVector.add(userName);
  }
  //删除用户名
  public void removeUserName(String userName){
  this.userNameVector.remove(userName);
  }
  //添加socket
  public void add(Socket socket){
  this.socketVector.add(socket);
  }
  //移除socket
  public void remove(Socket socket){
  this.socketVector.remove(socket);
  }
  //发消息给所有客户端
  private void send(String head,String message){
  PrintWriter pw = null; //输出流
  Socket sock;
  if(this.socketVector != null){
  for(int i=0;i0){
  StringBuffer sb = new StringBuffer();
  //循环用户名列表生成消息
  for(int i = 0;iFlex客户端中接收消息按此分隔获取用户名
  sb.append("-");
  }
  if(sb.length()>0){
  //去掉最后一个'-'分隔符号
  sb.deleteCharAt(sb.length()-1);
  }
  //发送给所有客户端
  this.send(USER_LIST, sb.toString());
  }
  }
  }
  [b][/b] 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics