一、实验内容
- 实验目的
掌握远程过程调用原理,基于java RMI进行远程编程和控制。要求定义远程接口类:定义相应的处理方法;客户端利用RMI实现远程调用服务。(笔者实现的是服务器端和客户端都在同一台电脑上) - 实验准备操作
下载或安装java jdk 1.6或以上(笔者用的版本是1.8.0_201);
熟悉IDEA或eclipse等开发环境(笔者用的版本是IDEA 2018.3.5)。 - 实验内容
利用RMI技术对远程文件夹进行控制:可以增加文件(文本文件)、修改文件(文本文件)、删除文件、列出文件;统计该文件夹具有多少个文件、占用磁盘空间的总大小。
二、实验过程
- 在IDEA中先新建一个名为rmi_test的java project;
- 在src文件夹中新建一个名为rmi_test的package;
- 在package rmi_test中新建一个Server(服务器端) Class,Client(客户端) Class,MyFileImpl Class(函数实现),MyFile Implement(函数声明),截图如下:
- Server代码如下:
package rmi_test;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
public class Server{
public Server() {}
public static void main(String args[]) {
System.setSecurityManager(new RMISecurityManager());//安全性管理器
final MyFileImpl obj = new MyFileImpl();
try { // 0 - anonymous TCP port ↓
MyFile stub = (MyFile)UnicastRemoteObject.exportObject(obj, 0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(9527);//设置端口号
registry.rebind("MyFile", stub);
System.err.println("Server ready....");
System.err.println("Listinging on port 9527 ....");
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyFile代码如下:
package rmi_test;
import java.io.File;
public interface MyFile extends java.rmi.Remote{
boolean createFile(String filePath) throws java.rmi.RemoteException;
boolean updateFile(String filePath, String str) throws java.rmi.RemoteException;
boolean deleteFile(String filePath) throws java.rmi.RemoteException;
File[] listFile(String folderPath) throws java.rmi.RemoteException;
int countFile(String folderPath) throws java.rmi.RemoteException;
double sizeFile(File file) throws java.rmi.RemoteException;
}
MyFileImpl代码如下:
package rmi_test;
import java.io.FileWriter;
import java.io.File;
import java.io.IOException;
public class MyFileImpl implements MyFile {
public MyFileImpl() {
}
public boolean createFile(String filePath) {
boolean flag = false;
File newFile = new File(filePath);
if (!newFile.exists()) {//如果文件不存在
try {
newFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
flag = true;
}
return flag;
}
public boolean updateFile(String filePath,String str) {
boolean flag = false;
File updateFile = new File(filePath);
if (updateFile.exists()) {
try{
FileWriter fw = new FileWriter(filePath,true);//true代表允许在文件后继续写入文件,否则将覆盖原文件
fw.write(str);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
flag = true;
}
return flag;
}
public boolean deleteFile(String filePath){
boolean flag = false;
File deleteFile = new File(filePath);
if(deleteFile.exists()) {
deleteFile.delete();
flag = true;
}
return flag;
}
public File[] listFile(String folderPath){
File folder = new File(folderPath);
return folder.listFiles();
}
public int countFile(String folderPath){
File folder = new File(folderPath);
return folder.listFiles().length;
}
public double sizeFile(File file){//递归计算文件夹大小,如果是文件,就加上文件的大小,如果是文件夹,就遍历加上文件夹的所有文件的大小,然后递归文件夹中的文件夹
if (file.isFile())
return file.length();
final File[] files = file.listFiles();
long size = 0;
if (files != null)
for (final File file1 : files)
size += sizeFile(file1);
return size;
}
}
Client代码如下:
package rmi_test;
import java.net.MalformedURLException;
import java.rmi.*;
import java.io.File;
import java.util.Scanner;
public class Client {
private Client() {
}
public static void main(String[] args) throws RemoteException, MalformedURLException,NotBoundException {
String host = (args.length < 1) ? "localhost" : args[0];
String urlo = "rmi://" + host + ":9527/MyFile";
MyFile stub = (MyFile) Naming.lookup(urlo);
System.out.println("link to the server: \n" + urlo);
File test = new File("D://test");//测试的文件夹放在D盘,并且命名为test
if(!test.exists()){//如果test文件夹不存在,那就新建一个文件夹,以下的所有文件夹操作都将在test文件夹内操作
test.mkdir();
}
Scanner input = new Scanner(System.in);//用以接收操作的指令
boolean flag = true;
while(flag){
System.out.println("input a number to select an operation:");
System.out.println("1 for creating a file");//新建文件
System.out.println("2 for updating a file");//修改文件(在文件后面添加数据)
System.out.println("3 for deleting a file");//删除文件
System.out.println("4 for listing files");//列出test文件夹里的所有文件和文件夹
System.out.println("5 for counting files");//计算test文件夹里所有文件和文件夹的个数
System.out.println("6 for outputting the size of files");//计算test文件夹下所有文件的大小
System.out.println("other number to exit");
switch (input.nextInt()) {
case 1:
System.out.println("name the file");
Scanner inputfilename1 = new Scanner(System.in);
String filename1 = inputfilename1.nextLine();
boolean cF = stub.createFile("D:/test/"+filename1+".txt");
if (cF) {
System.out.println("create a new file successfully!");
}
else{
System.out.println("file already exists");
}
break;
case 2:
System.out.println("choose a file");
Scanner inputfilename2 = new Scanner(System.in);
String filename2 = inputfilename2.nextLine();
System.out.println("input the content");
Scanner inputcontent = new Scanner(System.in);
String content = inputcontent.nextLine();
boolean uF = stub.updateFile("D:/test/"+filename2+".txt", content);
if (uF) {
System.out.println("update file successfully!");
}
else{
System.out.println("update unsuccessfully");
}
break;
case 3:
System.out.println("choose a file to delete");
Scanner inputfilename3 = new Scanner(System.in);
String filename3 = inputfilename3.nextLine();
boolean dF = stub.deleteFile("D:/test/"+filename3+".txt");
if(dF){
System.out.println("delete file successfully");
}
else{
System.out.println("delete file unsuccessfully");
}
break;
case 4:
File[] files = stub.listFile("D:/test/");
for(File file:files){
System.out.println(file.getName());
}
break;
case 5:
System.out.println("there are "+stub.countFile("D:/test/")+" files");
break;
case 6:
System.out.println(stub.sizeFile(new File("D:/test/"))+"bytes");
break;
default:{
flag = false;
}
}
}
}
}
-
配置policy文件
在rmi_test根目录下新建一个file,取名为policy.txt,截图如下:
文件内容如下:
grant {
permission java.net.SocketPermission "localhost:*","accept,listen,connect,resolve";//端口权限
permission java.io.FilePermission "D:\\*", "read,write,delete";
permission java.io.FilePermission "D:\\test\\*", "read,write,delete";//读写删权限
};
然后在
图中的地方配置
如红线区域所示,代码如下:
-Djava.security.policy=policy.txt
-
到此,实验过程已经完全结束,接下来就可以愉快地开始跑程序了。
server端的实验截图如下: client端的实验截图如下:
三、实验总结
总结
- 在传统的编程概念中,过程是由程序员在本地编译完成,并只能局限在本地运行的一段代码,也就是说主程序和过程之间的运行关系是本地调用关系。这种结构在网络日益发展的今天已无法适应实际需求,其调用模式无法充分利用网络上其他主机的资源,也无法提高代码在实体间的共享程序,使得主机资源大量浪费。
-
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口,它可以被看做是RPC的Java版本,支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。
- stub是代表远程对象的客户机端对象,stub通过RMI基础结构将请求转发到远程对象,实际上由远程对象执行请求。
- 在服务器端,skeleton对象处理远方的所有细节。
- RMI的优点:
- 可以连接现有/原有的系统:RMI可通过Java的本机方法接口JNI与现有系统进行交互。
- 编写一次,到处运行。
- 分布式垃圾收集:RMI采用其分布式垃圾手机功能收集不再被网络中任何客户程序所引用的远程服务对象。
- 并行计算:RMI采用多线程处理方法,可使您的服务器利用这些Java线程更好地并行处理客户端的请求。
重难点
- 一定,一定要配置好policy.txt文件,不然默认调用的java.policy文件权限是不够的,就会报错。
- Client里面利用stub调用函数,要把结果return回来,然后根据结果在client端显示,不能直接在函数里面显示结果,不然就会在server端显示,而client端不显示。
网友评论