Flex socket通信实践学习笔记(2)-1
2011年04月17日
[b]前[/b]面,阿堂和朋友们简单聊了一下,给出了一些FLEX和JAVA交互的操作图的界面一文(见 Flex socket通信实践学习笔记(1)),见阿堂的新浪空间(http://blog.sina.com.cn/s/blog_4c925dca0100s38p.ht ml),由于阿堂平常一直比较忙,所以代码没有粘出来,今天我就给出该操作图相应的后台服务端java代码和客户端的FLEX代码.对于flex和JAVA的交互,我这里也简单总结一下,谈一下自己的看法!
[b]1.flex和java交互时,需要三次握手过程,握手成功后,flex客户端会检测通信端口中是否存在安全策略文件,此时客户端发送以下报文内容.
[/b][b]
[/b] 服务端在收到该报文后,应该向客户端发送安全策略文件。
//Flex 安全策略文件
String xml ="";
xml = xml+"";
xml = xml+"";
xml = xml+"";
之后再进行正常Socket通信.
所以,朋友们会在阿堂后面粘出来的代码中看到有如下代码
if(head.equals("")){
pw.print(xml+"\0");
pw.flush();
}else{
...
}
代码的判断,对于安全策略文件,不是阿堂这篇文章讨论的重点,所以我就不再详细说明了。有兴趣的朋友可以继续看flex安全策略文件方面的介绍和说明,网上有很多这方面的介绍
[b] 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和服务端的交互.
[/b] (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
[b]服务端代码如下
[/b] 代码如下
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]
2011年04月17日
[b]前[/b]面,阿堂和朋友们简单聊了一下,给出了一些FLEX和JAVA交互的操作图的界面一文(见 Flex socket通信实践学习笔记(1)),见阿堂的新浪空间(http://blog.sina.com.cn/s/blog_4c925dca0100s38p.ht ml),由于阿堂平常一直比较忙,所以代码没有粘出来,今天我就给出该操作图相应的后台服务端java代码和客户端的FLEX代码.对于flex和JAVA的交互,我这里也简单总结一下,谈一下自己的看法!
[b]1.flex和java交互时,需要三次握手过程,握手成功后,flex客户端会检测通信端口中是否存在安全策略文件,此时客户端发送以下报文内容.
[/b][b]
[/b] 服务端在收到该报文后,应该向客户端发送安全策略文件。
//Flex 安全策略文件
String xml ="";
xml = xml+"";
xml = xml+"";
xml = xml+"";
之后再进行正常Socket通信.
所以,朋友们会在阿堂后面粘出来的代码中看到有如下代码
if(head.equals("")){
pw.print(xml+"\0");
pw.flush();
}else{
...
}
代码的判断,对于安全策略文件,不是阿堂这篇文章讨论的重点,所以我就不再详细说明了。有兴趣的朋友可以继续看flex安全策略文件方面的介绍和说明,网上有很多这方面的介绍
[b] 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和服务端的交互.
[/b] (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
[b]服务端代码如下
[/b] 代码如下
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]