前些日子的博客文章介绍了Flex怎样通过远程对象和JAVA通信,今天再和童靴们分享下Flex如何通过套接字和JAVA进行通信。
关于套接字通信的原理大家可以参看相关文档。简单地讲,套接字是OSI模型的会话层的一部分,会话层为两台计算机之间的数据流提供管理和控制服务,而套接字封装了两台计算机通信的具体实现细节,我们只要基于套接字建立起两台计算机的连接,则可以实现通信互发消息。被连接的一方是套接字服务端,而主动去申请连接的一方是套接字客户端,套接字服务端在特定的端口号监听,一旦监听到客户端的连接请求,则确认连接,双方完成握手,则可以互通往来。
具体到今天的案例来说,用JAVA建立起套接字服务,并在特定端口号监听,而Flex通过XMLSocket去连接JAVA套接字服务,一旦连接建立,两者则可以通信。
JAVA服务端:
还是跟上篇一样,先讲JAVA服务端的实现,java服务端主要有四个类,其中一个是套接字服务主类SocketSrv,用来创建套接字服务和负责监听;第二个类是请求处理类RequestHanlder,在监听到套接字客户端请求后,把请求交给该类分发处理;第三个类是个工具类FlexStringReader,用来对Flex串做特殊处理,这是因为flex里面的string发送过来是以\0结束的. java后台需要额外处理一下\0, 同样java返回的字符串也必须使用\0才能在flex客户端接收到; 第四个类是这个案例的业务场景类CellPhoneLocatorService.java,请求处理类RequestHanlder在收到请求调用它来响应相关请求并返回结果给客户端。
在这个案例中,编译和运行JDK版本都是1.4,java服务端程序基本上不用额外的jar包,因为套接字类都是JDK自带的,下面相关源码:
SocketSrv.java源码
public class SocketSrv {
/** The server socket */
private ServerSocket serverSocket = null;
/** The listening port of server. */
private int serverPort = 8888;
private int backlog = 50;
private InetAddress bindAddress = null;
private boolean stopServer = false;
public SocketSrv() throws IOException {
//创建套接字服务对象
this.serverSocket = new ServerSocket(serverPort, backlog, bindAddress);
System.out.println(new Date() + ": Starting server.");
}
public void service() throws IOException {
//开始服务,监听客户端
Socket clientSock = null;
Thread handler = null;
while (!this.stopServer //如果不停止服务且监听到的客户端套接字不为空则把请求给处理类处理
&& (clientSock = this.serverSocket.accept()) != null) {
handler = new Thread(new RequestHanlder(clientSock));
handler.start();
}
this.releaseResource();
}
public void releaseResource() {
//停止服务,释放资源
if (this.serverSocket != null)
try {
this.serverSocket.close();
this.serverSocket = null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
SocketSrv server = new SocketSrv();
try {
server.service();
} catch (IOException e) {
e.printStackTrace();
server.releaseResource();
}
}
}
RequestHanlder.java源码:
public class RequestHanlder implements Runnable {
private Socket sock = null;
private String command = "";
private String parameter = "";
public RequestHanlder(Socket pSock) {
this.sock = pSock;
}
public void run() {
FlexStringReader reader = null;
PrintWriter pw = null;
String line = null;
try {
System.out.println("Client:" + this.sock);
InputStream in = this.sock.getInputStream();
reader = new FlexStringReader(in, "UTF-8");
pw = new PrintWriter(this.sock.getOutputStream());//
while ((line = reader.readLine()).length() > 0) {//等待客户端输入命令串
this.parseRequest(line);
if ("where".equalsIgnoreCase(command)) {
//调用业务类处理响应命令
CellPhoneLocatorService phoneLocatorSrv = new CellPhoneLocatorService();
pw.write(phoneLocatorSrv.locateNumber(this.parameter ) + '\0');
pw.flush();
} else if ("quit".equalsIgnoreCase(command)
|| "exit".equalsIgnoreCase(command)) {
break;
} else {
pw.write("Oops, unknow command .\r\n\0");
pw.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//按该案例的规则去解析和分解命令串,实际应用中都会有自己的业务规则
private void parseRequest(String line) {
command = "";
parameter = "";
StringTokenizer tokens = new StringTokenizer(line, " \t\n\r\f\0", false);
int count = tokens.countTokens();
if (count > 0) {
this.command = tokens.nextToken();
if (count > 1)
this.parameter = tokens.nextToken();
}
System.out.println("Command=" + this.command + "\tParameter="+ this.parameter + "\r\n");
}
}
FlexStringReader.java 源码:
public class FlexStringReader extends InputStreamReader {
private StringBuffer buf = new StringBuffer();
public FlexStringReader(InputStream in) {
super(in);
}
public FlexStringReader(InputStream in, String charsetName)
throws UnsupportedEncodingException {
super(in, charsetName);
}
// Make sure it works.
public String readLine() throws IOException {
int oneChar = 0;
buf.setLength(0);
while ((oneChar = this.read()) != -1) {//不是结束标识符
if (oneChar == '\0')
break;
buf.append((char) oneChar);
}
return buf.toString();
}
}
CellPhoneLocatorService.java源码:
public class CellPhoneLocatorService {
private Map<String, String> questions = new HashMap<String, String>(5);
public CellPhoneLocatorService() {
questions.put("130", "130's from chinaunicom\r\n");
questions.put("131", "131's from chinaunicom\r\n");
questions.put("133", "133's from Chinatelecom\r\n");
questions.put("135", "135's from China Mobile\r\n");
questions.put("138", "138's from China Mobile\r\n");
}
public String locateNumber(String phoneNum) {
String location = this.questions.get(phoneNum);
return location == null ? (phoneNum + "'s Unknown") : location;
}
}
类都比较简单,源码也有注释,相信童靴们能看懂,类介绍完了就可以先运行下服务端,在myeclipse中直接运行SocketSrv类即可,大家可以看到控制台输出"Starting server.",说明套接字服务已经启动。
Flex客户端程序:
Flex中主要是通过XMLSocket类来处理套接字的通信,这样的代码网上很多,也不做太多解释,直接上代码FlexSocketClient.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="800" height="600" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.controls.Alert;
private var sock:XMLSocket = null;
//Initial the GUI
private function initApp():void {
}
//Click logon
private function connectServer(event:MouseEvent):void {
if (this.sock != null)
return;
this.sock = new XMLSocket();
//Refer to XMLSocket document, follow the sample here
this.configureListeners(this.sock);
this.sock.connect("192.168.7.32", 8888);//这里要和套接字服务端一致
this.sendButton.enabled = true;
}
public function send(data:Object):void {
this.sock.send(data);
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.CLOSE, closeHandler);
dispatcher.addEventListener(Event.CONNECT, connectHandler);
dispatcher.addEventListener(DataEvent.DATA, dataHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
}
private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
this.appendLine("CLose event socket");
}
private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
this.appendLine("Send: connect to server sucessfully." + event.target.toLocaleString());
}
private function appendLine(mesg:String):void {
//The /0 will be added automatically like C
this.messageArea.text += (mesg);
}
private function dataHandler(event:DataEvent):void {
trace("dataHandler: " + event);
this.appendLine("Server Response:" + event.data);
//this.messageArea.text += ("Server Response:" + event.target.toLocaleString() + "/r/n");
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
this.appendLine("Oops, ioError");
}
private function progressHandler(event:ProgressEvent):void {
trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
this.appendLine("Oops, encounter security error:" + event.text);
}
private function sendMessage(event:MouseEvent):void {
var message:String = this.messageField.text;
message = message + " /r/n";
if (message != null && message.length > 0) {
this.send(message);
this.appendLine("Send:" + message );
}
}
]]>
</mx:Script>
<mx:TextArea x="10" y="10" width="480" height="186" id="messageArea"/>
<mx:TextInput x="10" y="216" width="300" height="31" id="messageField"/>
<mx:Button x="327" y="216" label="Send" height="31" width="69" id="sendButton" enabled="false" click="sendMessage(event)"/>
<mx:Button x="399" y="216" label="Logon" height="31" id="logonButton" click="connectServer(event)"/>
</mx:Application> 代码在Flex Bulider3工程中编译会生成FlexSocketClient.swf,运行它界面如下:
点login按钮,如果连接成功,会提示:Send: connect to server sucessfully.[object XMLSocket],同时JAVA控制台也会输出相关信息,这之后你可以按该案例的业务场景发送相关命令串,两者通信完成。如果你想停止连接,发送quit或exit则套接字连接终止,此后你再发送相关命令串则会提示异常。
好了,Flex怎样通过套接字和JAVA通信就介绍到这,想进一步了解,请关注后续博客文章。