分享
 
 
 

用RMI编写网络应用程序

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

从Java入门至今已有一年光景.现在谈谈一年心得.首先,Java基础是必须学好的,必须掌握Java的语法规则.接下来

就是awt下的Grahpics和swing包,应用程序编程必学,io下面也是极其重要的内容,再就到了网络编程方面,刚开始接触到

的是Socket编程,初学Java两个月便用Socket编程写"四国大战"(因为我对联众四国大战特有兴趣),写这个游戏整整花了

我一个月时间,每天是上课编程,下课编程,每天晚上忙到12点,甚至做梦也在编程,一个月后,整完了,四国大战也可以正常

开战了,心里乐滋滋的,这就是编程的乐趣.然而初学两个月的Java(Java是我学习的第一门而向对象的编程语言),写出来

的东西结构混乱不堪,用记事本写的几千行的代码搞得我连加功能都不知道去哪儿,于是我决定对其进行改版,这回我选择

JCreator,这是个不错的Java编程工具,找个方法也没那么费劲了,省了我不少时间,建立好整个游戏系统的框架,我准备开

始"动手"实现功能了,于是第一步便遇到自己设计应用程序级协议,这是一个头疼的问题,命令设计就让人头大,还得考虑网

络数据安全性问题,如何通过防火墙,我一筹莫展,整个系统也耽搁了好长时间,因为还有工作(JSP开发企业应用).一次查资

料的偶然,我看到了RMI,带着好奇心,我看了入门,这时我有这么一个感觉,这个东东能不能帮我实现网络对话,而不用自已

写协议?果然,它能做到!我感觉到Java实在是太强大了,使用RMI写网络应用程序,不用自已设计协议,不用自己考虑数据安全,

不用考虑网络防火墙.我的血液沸腾了.用两天看完RMI基础,测试了Hello, world后,我操起了RMI继续我的游戏系统"革命".

在这儿,我不准备详细介绍我的游戏系统,因为我还没有时间去完全实现它的功能.在这里我想通过一个简单的网络应用(聊

天室)来向各位初涉RMI介绍RMI.

第一步,让我们来看看聊天室能做些什么.我们的聊天室准备实现最简单的功能,大家一起聊天.于是客户端需要一个显示

聊天内容的文本域,一个发送消息的文本框,和一个发送按钮.为支持HTML语法消息,刚才的文本域可以使用JTextPane;我们

的服务器需要知道往哪几个聊天内容显示区域中发送消息,于是,聊天内容显示域必须在服务器上注册.因此它必须是可以序

列化到服务器的.为让服务器可以给它发送消息,它必须有一个可以在远程调用的方法,于是它本身得实现Remote接口,而Remote

接口是空接口,于是,我们得写一个接口继承Remote接口,在这个接口中,我们声明一个可以在服务器端调用的方法:

appendChatContent(String msg).让我们来先"搞定"这个接口ChatViewerInterface:

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface ChatViewerInterface extends Remote

{

void appendChatContent(String msg) throws RemoteException;

}

这个接口写完了,如果服务器需要更多的操作,可定义多个方法,这些方法必须抛出RemoteException,然后再实现这个接口.

接下来,我们看看聊天内容显示域类ChatViewer的代码(这儿,我们将它与滚动面板绑在一起,实现聊天内容的滚动):

import java.rmi.*;

import java.rmi.server.*;

import javax.swing.*;

import java.io.*;

import javax.swing.text.*;

import javax.swing.text.html.*;

import javax.swing.event.*;

import java.text.*;

public class ChatViewer extends JComponent implements ChatViewerInterface,Serializable

{

JScrollPane scrollpane;

JTextPane viewer;

public ChatViewer()

{

this.initializedComponent();

}

public ChatViewer(String inimsg)

{

this.initializedComponent();

this.viewer.setText(inimsg);

}

private void initializedComponent()

{

this.viewer = new JTextPane();

this.viewer.setContentType("text/html;charset=gb2312");

this.viewer.setEditable(false);

this.viewer.addHyperlinkListener(new LinkListener());

this.scrollpane = new JScrollPane(this.viewer);

this.setLayout(new BorderLayout());

this.add(this.scrollpane,BorderLayout.CENTER);

}

public void appendChatContent(String msg)

{

HTMLEditorKit kit = (HTMLEditorKit)(this.viewer.getEditorKit());

Document doc = this.viewer.getDocument();

StringReader reader = new StringReader(msg);

try{

kit.read(reader,doc,doc.getLength());

}catch(Exception e){System.out.println("chat content \""+msg+"\" lost..");}

//实现自动滚动

if(this.viewer.getSelectedText()==null||this.viewer.getSelectedText().trim().length()==0)

{

this.viewer.select(this.viewer.getText().length(),this.viewer.getText().length());

}

}

public void sendToServer()

{

try{

UnicastRemoteObject.exportObject((ChatViewerInterface)this);

}catch(Exception e){

System.out.println("send object to server error: "+e.getMessage());

}

}

class LinkListener implements HyperlinkListener

{

public void hyperlinkUpdate(HyperlinkEvent e)

{

if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)

{

if(e instanceof HTMLFrameHyperlinkEvent)

{

HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e;

HTMLDocument doc = (HTMLDocument)(viewer.getDocument());

doc.processHTMLFrameHyperlinkEvent(evt);

}

else

{

try {

Runtime.getRuntime().exec("explorer "+e.getURL());

}

catch(Exception ioe) {

MessageDialog.showMessage(null,Informations.UNSUPPORTED_BROWSER);

}

}

}

}

} //内部类

}

在这儿,我介绍一下sendToServer()这个方法,这个方法用于将自身对象序列化到服务器端,服务器端将这些对象注册.

然后我们写一个窗口,来完成客户端的工作.在这个类中,我们要用一个按钮来向服务器发送消息,服务器也是一个远程

对象,我们把这个类命名为ServerForChat,它也实现一个远程接口ServerForChatInterface.在写完这些代码后,我们来

一起看看它们是怎么工作的.

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class ClientForm extends JFrame

{

private ChatViewer chat;

private JTextField megeditor;

private JButton msgsender;

private Container contentpane;

private JPanel panel;

private ServerForChatInterface server;

public ClientForm(String serveraddress,int port)

{

super("简易聊天室");

try{

this.server = Naming.lookup("rmi://"+serveraddress+":"+port+"/ChatServer");

}catch(Exception e){

System.out.println("不能连接到服务器.");

System.exit(0);

}

this.initializedComponent();

this.fireEvent();

this.registChatViewer();

}

private void initializedComponent()

{

this.chat = new ChatViewer("<font color='blue'>欢迎进入聊天室</font>");

this.msgeditor = new JTextField();

this.msgsender = new JButton("发送");

this.panel = new JPanel();

this.panel.setLayout(new BorderLayout());

this.panel.add(this.msgeditor,BorderLayout.CENTER);

this.panel.add(this.msgsender,BorderLayout.EAST);

this.contentpane = this.getContentPane();

this.contentpane.setLayout(new BorderLayout());

this.contentpane.add(this.chat,BorderLayout.CENTER);

this.contentpane.add(this.panel,BorderLayout.SOUTH);

}

private void fireEvent()

{

MessageSender ms = new MessageSender();

this.msgeditor.addActionListener(ms);

this.msgsender.addActionListener(ms);

this.msgeditor.grabFocus();

}

private void chat()

{

String msg = this.msgeditor.getText();

this.msgeditor.setText("");

try{

this.server.chat(msg);

}catch(Exception e){

this.chat.appendChatContent(<font color='red'><b>发送消息失败,请检查网络.</b></font>);

}

}

private void registChatViewer()

{

try{

UnicastRemoteObject.exportObject((ChatViewerInterface)(this.chat));

this.server.regist((ChatViewerInterface)(this.chat));

}catch(Exception e){

this.chat.appendChatContent(<font color='red'><b>连接服务器失败,请检查网络.</b></font>);

}

}

class MessageSender implements ActionListener

{

public void actionPerformed(ActionEvent e)

{

chat();

}

}

public static void main(String args[])

{

String serveraddress = "127.0.0.1";

int port = 1099;

if(args!=null&&args.length==2)

{

serveraddress = args[0];

try{

port = Integer.parseInt(args[1]);

}catch(Exception e){}

}

ClientForm client = new ClientForm(serveraddress,port);

}

}

客户端的工作完成了,它需要与服务器交互的地方:1.到服务器注册自身聊天内容显示域的对象,通过调用服务器的regist(ChatViewerInterface client)方法.

2.它向服务器发送聊天消息,请求服务器发送消息给其他在线用户,通过调用服务器的chat方法.所以,我们的服务器至少

包括两个远程方法:regist和chat,我们开始编写服务器远程接口ServerForChatInterface.

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface ServerForChatInterface extends Remote

{

void regist(ChatViewerInterface client) throws RemoteException;

void chat(String msg) throws RemoteException;

}

服务器远程接口定义完成,我们开始编写服务器实现代码.

import java.rmi.*;

import java.rmi.server.*;

import java.util.Vector;

import java.rmi.registry.*;

public class ServerForChat extends UnicastRemoteObject implements ServerForChatInterface

{

private static Vector clients = new Vector();

private int port = 1099;

public ServerForChat() throws RemoteException

{

super();

}

public ServerForChat(int port) throws RemoteException

{

super(port);

this.port = port;

}

public void regist(ChatViewerInterface client)

{

if(clients.contains(client)==false)

{

clients.add(client);

}

}

public void chat(String msg)

{

for(int i = 0;i<clients.size();i++)

{

try{

((ChatViewerInterface)(clients.elementAt(i))).appendChatContent(msg);

}catch(Exception e){

clients.remove(i);

continue;

}

}

}

public static void main(String args[])

{

int port = 1099;

if(args!=null&&args.length==1)

{

try{

port = Integer.parseInt(args[0]);

}catch(Exception e){}

}

try{

LocateRegistry.createRegistry(port);

ServerForChat server = new ServerForChat(port);

Naming.rebind("rmi://localhost:"+port+"/ChatServer",server);

}catch(Exception e){

System.out.println("start sever fail...");

System.exit(0);

}

System.out.println("server started on port: "+port);

}

}

整个代码完成了,你是不是感到兴奋,在你熟悉了RMI的机制后,你认为你需要超过半个小时来写一个简单的网络应用

吗?

编译上述代码:

javac (path)\*.java

rmic -v1.2 ChatViewer

rmic -v1.2 ServerForChat

接着我们启动服务器:

java ServerForChat [port]

JVM将启动RMI注册表,在注册表中将保存可供远程调用的对象,远程JVM通过查找网络上的RMI注册表Naming.lookup(String url),

找到位于远程计算机JVM上的对象,你便可以像使用本地JVM对象一样使用远程对象了.而通过UnicastRemoteObject.export(Remote)

则可以直接将本地对象序列化到远程JVM,远程JVM接收到此对象,也可以像使用本地对象一样使用该对象.具体的RMI实现

及残根码,框架码等等概念可参考RMI入门相关书籍.另外值得一提的是Java提供的RMI安全机制,以及HTTP隧道的概念,

感兴趣的读者可详细阅读RMI相关书籍.欢迎与我联系,联系信箱:zlbbq47054370@sina.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有