[转]Flex和java的socket通信
服务端:java jdk1.5 (使用工具:eclipse3.2)
客户端:flex 2
(一)连接
目的:实现flex和java的连接
服务端代码:Server1.java
import java.net.*;
import java.io.*;
public class Server1 {
public static void main(String[] args) {
ServerSocket server=null;
try{
server=new ServerSocket(8888);
//x1
System.out.println("服务器套接字已经被创建");
while(true){
System.out.println("等待客户机");
Socket newSocket=server.accept();//x2
System.out.println("已与客户机连接");
}
}catch(IOException ie)
{
System.out.println(ie);
}finally{
Try
{
if(server!=null) server.close();//x3
}catch(IOException ie){}
}
}
}
知识点:
X1:使用指定的端口号创建了一服务器套接字对象。
X2:调用accept()方法来等待客户机的连接请求。
X3:关闭服务器套接字。如果一直没有客户机器提出连接请求,服务器套接字将会继续等待。
编译后运行如图:

客户端代码:Client1.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creati f width="349" height="326">
<mx:Script>
<![CDATA[
import flash.net.Socket; //导入类包
private var socket:Socket;
//创建Socket对象
internal function initApp():void
{
socket=new Socket(); //new出来,这时候才能被使用
socket.connect("127.0.0.1",8888); //连接服务器
socket.addEventListener(Event.CONNECT,funConnect);
//监听是否连接上服务器
socket.addEventListener(Event.CLOSE,funClose);
//监听服务器是否关闭
}
private function funConnect(event:Event):void
{
myText.text+="已经成功连接到服务器!\n";
}
private function funClose(event:Event):void
{
myText.text+="和服务器断开!\n"
}
]]>
</mx:Script>
<mx:TextArea x="10" y="10" width="327" height="309" id="myText"/>
</mx:Application>
界面很简单,就是拖了一个TextArea组件来记录连接状态。
运行结果

http://www.greenidea.net/files/源文件.rar
知识点:
在as3.0中,所有和网络通信有关的类都位于flash.net包中,这里使用的是Socket类对象。
下买你用Socket 对象建立一个新的Socket对象:
var socket:Socket=new Socket();
或者
var socket:Socket=new Socket(“127.0.0.1”,8888);
这条语句设置了服务器地址为127.0.0.1 端口是8888
当指定了了服务器地址和端口,Socket对象将自动开始连接服务器。如果不指定,则需要条用connect方法才开始执行连接动作,比如:
var socket:Socket=new Socket();
socket.connect(“127.0.0.1”,8888);
完成连接动作后,接下来要获取服务端得返回信息。Socket对象利用时间机制来处理服务器端的信息,我们只要给Socket对象添加相关的事件监听函数就可以捕捉到服务器端的信息,Socket对象的事件主要有:
1 Event.CLOSE 连接中断事件。
2 Event.CONNECT 连接状态事件,表示已经成功连接了服务器。
3 IOErrorEvent.IO_ERROR 信息传递错误事件,一般是由服务器地址错误引起的。
4 ProgressEvent.SOCKET_DATA 服务器信息事件,当收到服务器的新信息时被触发。
(二)单向通信
目的:客户端向服务端发消息,服务端将消息显示在屏幕上,不给客户端发送任何数据。
服务器将反复进行一下过程。
1 等待客户机连接请求
2 连接客户机
3 在断开客户机连接之前,接收字符串
4 断开客户机连接
5 返回至第一步
获取与客户机连接的套接字的输入流,过程如下。
Socket socket=server.accept(); //返回与客户机连接的套接字
InputStream is=socket.getInputStream(); //获取套接字的InputStream
InputStreamReader isr=new InputStreamReader(is);
BufferedReader reader= new BufferedReader(isr); //字符串流
服务端代码:Server2.java
=========================================
import java.net.*;
import java.io.*;
public class Server2 {
private BufferedReader reader; //负责输入
private ServerSocket server; //服务器套接字
private Socket socket; //套接字
public Server2(){} //缺省构造函数
void startServer() //启动服务器
{
try
{
server=new ServerSocket(8888); //创建服务器套接字
System.out.println("服务器套接字建立完毕");
while(true)
{
System.out.println("等待客户机");
socket=server.accept(); //若客户机提出连接请求,与socket连接
System.out.println("完成与客户机的连接");
//获取socket输入流,“utf-8”这个编码设置是为了更好显示中文
reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
getMessage();//读取来自客户机的数据,并输出至画面上
}
}catch(Exception e)
{
System.out.println(e);
}
}
void getMessage() //读取来自套接字的信息
{
try
{
while(true) //循环
{
System.out.println("客户机:"+reader.readLine());
}
}catch(Exception e){}
finally{
System.out.println("客户机中断连接");
try
{
if(reader!=null) reader.close(); //关闭套接字的输入流
if(socket!=null) socket.close(); //关闭套接字
reader=null;
socket=null;
}catch(Exception e){}
}
}
public static void main(String[] args)
{
Server2 server=new Server2();
server.startServer();
}
}
======================================
客户端代码:Client2.mxml
==================================================================================
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontSize="12" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import flash.net.Socket; //导入类包
import flash.utils.ByteArray; //ByteArray用来在读取数据的时候使用
private var socket:Socket=new Socket(); //定义Socket
//初始化程序
internal function initApp():void
{
socket.connect("127.0.0.1",8888); //连接服务器
socket.addEventListener(Event.CONNECT,funConnect); //监听是否连接
socket.addEventListener(Event.CLOSE,funClose); //监听连接关闭
}
internal function funConnect(event:Event):void
{
myText.text+="连接已建立 \n";
}
internal function funClose(event:Event):void
{
myText.text+="连接已关闭 \n";
}
internal function sendMessage(msg:String):void//发送数据对应按钮click事件
{
var message:ByteArray=new ByteArray();//新建一个ByteArray存放数据
//写入数据,writeUTFBytes方法,以utf-8格式传数据避免中文乱码
message.writeUTFBytes(msg +"\r\n");
socket.writeBytes(message); //写入Socket的缓冲区
socket.flush(); //调用flush方法发送信息
myText.text+=msg+"\r\n"; //在客户端屏幕上输出发送的内容
myInput.text=""; //清空发言框
}
]]>
</mx:Script>
<mx:TextArea x="10" y="10" width="703" height="263" id="myText"/>
<mx:TextInput x="10" y="297" width="605" id="myInput"/>
<mx:Button x="648" y="297" label="发送" id="myBtn" click="sendMessage(myInput.text)"/>
</mx:Application>
=======================================
知识点在(一)中已经讲过,就不重复了。
运行效果
服务端

客户端

(三)多客户通信
目的:做一个简单的多玩家多线程的猜拳游戏。每个客户机都与服务端的一个套接字进行通信,但是各个客户机之间不进行通信。服务器受到客户机的连接请 求时会创建新的套接字并使其与客户机连接。然后启动线程与客户机进行数据交换。套接字管理器是一个Vector,用于管理套接字的个数及其连接状态。
游戏描述:玩家通过向服务器发送0,1,2这个三个数字,用来代表剪刀,锤包,袱。服务器接到信息后会随机产生0,1,2这三个数字的其中的一个。在客户机上通过比较来进行判断输赢。
先放效果图
服务端:

客户端:

服务端代码:Server4.java
=========================================
import java.net.*;
import java.io.*;
import java.util.*;
public class Server4 {
private ServerSocket server;
Vector sManager=new Vector();//管理套接字的Vector
Random rnd=new Random();//创建随机数的发生器
public Server4(){}
void startServer() //运行服务器
{
try
{
server=new ServerSocket(8888);
System.out.println("服务器套接字已创建成功!");
while(true)
{
Socket socket=server.accept();
System.out.println("已经与客户机连接");
new KBBCom_Thread(socket).start();
sManager.add(socket);
System.out.println("当前客户机连结数:"+sManager.size());
}
}catch(Exception e){}
}
public static void main(String[] args) {
Server4 server=new Server4();
server.startServer();
}
class KBBCom_Thread extends Thread //与客户机进行通信的线程累
{
Socket socket; //套接字引用变量
private DataInputStream reader; //套接字输入流
private DataOutputStream writer; //套接字输出流
KBBCom_Thread(Socket socket) //构造函数
{
this.socket=socket;
}
public void run()
{
try
{
//获取套接字的输入输出流
reader=new DataInputStream(socket.getInputStream());
writer=new DataOutputStream(socket.getOutputStream());
String msg;
//如果收到客户端发来的数据
while((msg=reader.readUTF())!=null)
{
//向客户机传送0-2之间的整型随机数
writer.writeUTF(rnd.nextInt(3)+"\n");
writer.flush();
System.out.println("来自客户机:"+msg);
}
}catch(Exception e){}finally
{
try
{
sManager.remove(socket); //删除套接字
//关闭输入输出流及套接字
if(reader!=null)reader.close();
if(writer!=null)writer.close();
if(socket!=null)socket.close();
reader=null;
writer=null;
socket=null;
//向屏幕输出相关信息
System.out.println("客户机离开");
System.out.println("当前客户机的连接数:"+sManager.size());
}catch(Exception e){}
}
}
}
}
=====================================
知识点:套接字管理器(Vector)会将于客户机连接的套接字添加到其列表中,在客户机断开连接后,在将相应的套接自从列表中删除,从中可以看出,客户机连接数与列表中添加套接字数目是一致的。
Vector sManager=new Vector();
sManager.add(socket); // 向列表添加套接字
sManager.remove(socket); //从列表移除套接字
sManager.size(); //获取客户机连接数
客户端代码:Client4.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontSize="12" creationComplete="initApp()" width="353" height="336">
<mx:Script>
<![CDATA[
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.events.ProgressEvent;
private var socket:Socket=new Socket();
private var intClient:int;//定义客户端数字出拳
private var intServer:int; //定义服务端数字出拳
private var intSY:int; //定义输赢判断
private var strClient:String; //客户端文字出拳
private var strServer:String; //服务端的文字出拳
internal function initApp():void
{
socket.connect("127.0.0.1",8888);
socket.addEventListener(Event.CONNECT,funConnect);
socket.addEventListener(Event.CLOSE,funClose);
socket.addEventListener(ProgressEvent.SOCKET_DATA,funSocket);
}
internal function funConnect(event:Event):void
{
myText.text+="连接已建立 \n";
}
internal function funClose(event:Event):void
{
myText.text+="连接已关闭 \n";
}
internal function sendMessage(msg:String):void
{
var message:ByteArray=new ByteArray();
message.writeUTF(msg); //发送出拳数字
socket.writeBytes(message);
socket.flush();
intClient=int(msg);
switch(intClient) //将数字转换成文字用于发布到屏幕上
{
case 0:
strClient="剪刀";
break;
case 1:
strClient="锤";
break;
case 2:
strClient="包袱";
break;
}
myText.text+="你出:"+strClient+"; ";
myInput.text="";
}
internal function funSocket(event:ProgressEvent):void //接到服务器信息
{
var msg:String="";
while(socket.bytesAvailable)
{
msg=socket.readUTF();
intServer=int(msg);
intSY=intClient-intServer; //通过数值判断输赢
switch(intServer) //将数字转换成文字用于发布到屏幕上
{
case 0:
strServer="剪刀";
break;
case 1:
strServer="锤";
break;
case 2:
strServer="包袱";
break;
}
myText.text+="服务器出:"+strServer+"; ";
//判断输赢的算法
if(intSY>0&&intSY<2)
{
myText.text+=" 结果:你赢了 \n";
}else if(intClient==intServer)
{
myText.text+=" 结果:平手 \n";
}else if(intSY<0&&intSY>-2)
{
myText.text+=" 结果:你输了 \n";
}else if(intSY>=2)
{
myText.text+=" 结果:你输了 \n";
}else if(intSY<=-2)
{
myText.text+=" 结果:你赢了 \n";
}
myText.verticalScrollPosition = myText.maxVerticalScrollPosition;// myText滚动到最下面
}
}
]]>
</mx:Script>
<mx:TextArea x="10" y="32" width="331" height="263" id="myText"/>
<mx:TextInput x="10" y="303" width="245" id="myInput"/>
<mx:Button x="273" y="304" label="发送" id="myBtn" click="sendMessage(myInput.text)"/>
<mx:Label x="10" y="10" text="规则:0代表剪刀;1代表锤;2代表包袱" width="331" fontWeight="bold"/>
</mx:Application>
附录:
参考资料
《java编程基础,应用与实例》 [韩]徐明浩著 武传海译 人民邮电出版社
《flex 第一步》 邱彦林著 清华大学出版社
http://www.greenidea.net/files/源文件1.rar
(四)一个简单的聊天室
目的:做一个简单的聊天室,用来实现消息广播。
服务端:

客户端:

服务端代码:Server5.java
import java.net.*;
import java.io.*;
import java.util.*;
public class Server5 {
private ServerSocket server;
private BManager bMan=new BManager();//消息广播者
public Server5(){} //构造函数
void startServer() //启动服务器
{
try{
server=new ServerSocket(8888); //创建服务器套接字
System.out.println("服务器套接字建立完毕");
while(true)
{
Socket socket=server.accept();//若客户机提请求,socket连接
new Chat_Thread(socket).start();//启动线程
bMan.add(socket);//添加套接字
bMan.sendClientInfo();//使用套接字输出当前聊天人数
}
}catch(Exception e){
System.out.println(e);
}
}
public static void main(String[] args) {
Server5 server=new Server5();
server.startServer();
}
class Chat_Thread extends Thread //与客户机进行通信的线程累
{
Socket socket; //套接字引用变量
private BufferedReader reader;//引用套接字输入流;
private PrintWriter writer;//引用套接字输出流;
Chat_Thread(Socket socket)//构造函数
{
this.socket=socket;
}
public void run()
{
try
{
reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf8"));
writer=new PrintWriter(socket.getOutputStream(),true);
String msg;
//从输出流获取信息
while((msg=reader.readLine())!=null)
{
System.out.println(msg);
//向所有客户机传送信息
bMan.sendToAll(msg);
}
}catch(Exception e)
{
}finally
{
try {//从消息广播者立标中删除socket
bMan.remove(socket);
if(reader !=null) reader.close();
if(writer !=null) writer.close();
if(socket !=null) socket.close();
reader=null;
writer=null;
socket=null;
System.out.println("客户机离开");
//向所有客户机传送当前连接数
bMan.sendClientInfo();
} catch (Exception e) {}
}
}
}
}
//消息广播者类,继承Vector类
class BManager extends Vector
{
BManager (){}//构造函数
void add(Socket sock)
{
super.add(sock);//添加套接字
}
void remove(Socket sock)
{
super.remove(sock);//删除套接字
}
//向所有客户机传送消息,同步化方法。
synchronized void sendToAll(String msg)
{
PrintWriter writer=null; //输出流
Socket sock; //套接字
for(int i=0;i<size();i++) //执行循环
{
sock=(Socket)elementAt(i);//获取第i个套接字
try
{ //获取第i个套接字输出流
writer=new PrintWriter(sock.getOutputStream(),true);
}catch(Exception ie){}
//使用第i各套接字输出流,输出消息
if(writer!=null) writer.println(msg);
}
}
//向所有客户机发送当前聊天人数
synchronized void sendClientInfo()
{
String info="当前聊天人数:"+size();
System.out.println(info);
sendToAll(info);
}
}
知识点:消息广播者类名为Bmanager,他继承了Vector类
class Bmanager extends Vector
{
Bmanager(){}
void add(Socket socket)
{
//添加套接字
}
void remove(Socket socket)
{
//删除套接字
}
synchronized void sendToAll(String msg)
{‘
//使用套接字的输出流,输出消息
}
synchronized void sendClientInfo()
{
//使用套接字的输出流,输出当前聊天人数
}
}
客户端代码:Client5.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontSize="12" creationComplete="initApp()" width="369" height="326">
<mx:Script>
<![CDATA[
import flash.net.Socket; //导入类包
import flash.utils.ByteArray;//ByteArray在读取数据时使用
private var socket:Socket=new Socket();//定义socket
internal function initApp():void
{
socket.connect("127.0.0.1",8888);//执行连接
//监听连接成功事件
socket.addEventListener(Event.CONNECT,funConnect);
//监听关闭事件
socket.addEventListener(Event.CLOSE,funClose);
//监听服务器新信息
socket.addEventListener(ProgressEvent.SOCKET_DATA,funSocket);
}
internal function funConnect(event:Event):void
{
myText.text+="连接已建立 \n";
}
internal function funClose(event:Event):void
{
myText.text+="连接已关闭 \n";
}
internal function sendMessage(msg:String):void //发送数据到服务器
{
//新建一个ByteArray来存放数据
var message:ByteArray=new ByteArray();
//写入数据,使用writeUTFBytes以utf8格式传数据,避免中文乱码
message.writeUTFBytes(msg+"\n");
//写入socket的缓冲区
socket.writeBytes(message);
//调用flush方法发送信息
socket.flush();
//清空消息框
myInput.text="";
}
//接受服务器信息
internal function funSocket(event:ProgressEvent):void
{
var msg:String="";
//循环读取数据,socket的bytesAvailable对象存放了服务器传来的所有数据
while(socket.bytesAvailable)
{
//强制使用utf8格式,避免中文乱码
msg+=socket.readMultiByte(socket.bytesAvailable,"utf8");
//使用\n换行符号把信息切开
var arr:Array=msg.split('\n');
for(var i:int=0;i<arr.length;i++)
{
if(arr[i].length>1)
{
//正则表达式,回车符
var myPattern:RegExp=/\r/;
//删除回车符
arr[i]=arr[i].replace(myPattern,'');
//在聊天框中输出
myText.text+=arr[i]+"\n";
}
}
myText.verticalScrollPosition = myText.maxVerticalScrollPosition;//滚动到最下面
}
}
]]>
</mx:Script>
<mx:TextArea x="10" y="42" width="344" height="247" id="myText"/>
<mx:TextInput x="10" y="297" width="270" id="myInput"/>
<mx:Button x="288" y="298" label="发送" id="myBtn" click="sendMessage(myName.text+':'+myInput.text)"/>
<mx:TextInput x="10" y="10" width="344" text="名字" id="myName"/>
</mx:Application>