rmid使用介绍

本文介绍了rmid工具及其在Java远程方法调用(RMI)中的作用,详细讲解了如何使用rmid启动激活进程,以及如何结合rmiregistry进行对象注册与查找,通过实例演示了整个过程。

    很多人知道rmic工具(为远程对象生成 stub 和 skeleton),但是却很少人了解rmid,笔者在这里介绍一下rmid,并简单谈谈它的使用,rmid像rmic一样,
是一个可执行程序,用于启动系统激活进程,以便能够在 Java 虚拟机上注册和激活对象。 rmid的出现是为了解决分布式处理的性能问题,如果一个系统存在
着大量的分布式对象,而对象无限期存在于内存中并一直保持活动状态,这将占用太多系统资源,另外,客户机需要保存对对象的持久引用的能力,这样在一个
系统崩溃后可以重新建立对象之间的通讯。为了解决这些问题,就有了RMI激活架构,可以让对象在需要时激活,不需要时就钝化。关于RMI激活概念,读者可以
参看http://www.oneedu.cn/xxyd/Print.asp?ArticleID=4277&Page=1。
    一般应用会把rmid和rmiregistry结合起来使用,一个专门用于激活和钝化,另外一个专门用于注册和查找,其实,rmid也有注册和查找对象的功能,所以
我们可以单独使用rmid来做rmi测试,我们先举一个例子说明,

先启动rmid,
rmid -J-Djava.security.policy=%LOCATION%/test.policy -port 1099
rmid在1099端口监听,默认是1098,现在用1099,目的很简单,替换rmiregistry。这里的LOCATION是指poliy文件存放的位置,
我们可以写一个全权开放的policy文件,
策略文件test.policy
grant {
 permission java.security.AllPermission;
};

我们的server程序如下,
接口Server.java
package com.lxj;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Server extends Remote{
 String say() throws RemoteException;
}
实现类Server1Impl.java
package com.lxj.test1;
import java.rmi.MarshalledObject;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.activation.Activatable;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.util.Properties;
import com.lxj.Server;
public class Server1Impl extends Activatable implements Server {
 public Server1Impl(ActivationID id, MarshalledObject data) throws RemoteException {
  super(id, 0);
 }
 public String say() throws RemoteException {
  System.out.println("begin say invoking");
  return "hello,world";
 }
 public static void main(String[] args) throws Exception{
    System.setSecurityManager(new RMISecurityManager());
     Properties props = new Properties();
     props.put("java.security.policy", "D:/ae_eclipse/workspace/test/bin/test.policy");
     ActivationGroupDesc.CommandEnvironment ace = null;
     ActivationGroupDesc group = new ActivationGroupDesc(props, ace);
     System.out.println("Begin register group");
    System.setProperty("java.rmi.activation.port","1099");
     ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(group);
     System.out.println("End register group");
     String location = "file:/D:/ae_eclipse/workspace/test/bin/";
     MarshalledObject data = null;
     ActivationDesc desc = new ActivationDesc(agi, "com.lxj.test1.Server1Impl", location, data);
     Server server = (Server)Activatable.register(desc);
     Naming.bind("Server",server);
     System.out.println("Exported Server");
 }
}
注:读者自己测试时请替换程序中的路径为自己本机的路径。
运行Server1Impl对服务进行注册,注意设置CLASSPATH,
java -Djava.security.policy=%LOCATION%/test.policy -Djava.rmi.server.codebase=file:/%LOCATION_2%/ com.lxj.test1.Server1Impl
LOCATION_2是指class文件的位置,运行完毕,如果没有错误表明已经注册激活组成功。
现在我们可以用客户端类来调用我们的服务,
package com.lxj.test1;
import java.rmi.Naming;
import com.lxj.Server;
public class Client1 {
 public static void main(String[] args) throws Exception {
  Server server = (Server) Naming.lookup("Server");
  //如果是远程服务,可以切换用下面注释掉的代码
  //Server server = (Server)java.rmi.registry.LocateRegistry.getRegistry("localhost",1099).lookup("Server");
  System.out.println(server.say());
 }
}
运行Client1以后,我们会发现在服务器进程列表中多了一个java进程,这个进程是rmid的子进程,每个激活组都会有一个jvm进程。


下面我们可以让rmid和rmiregistry一起工作,不过我们先要小小地调整一下Server1Impl.java代码,把
System.setProperty("java.rmi.activation.port","1099");这句话注释掉然后重新编译,因为现在rmiregistry要使用1099端口,
rmid还是使用它的1098,当然,这些端口号都可以修改。
先启动rmid,
rmid -J-Djava.security.policy=test.policy
然后启动rmiregistry
rmiregistry
再注册激活组和注册虚拟引用
java -Djava.security.policy=%LOCATION%/test.policy -Djava.rmi.server.codebase=file:/%LOCATION_2%/ com.lxj.test1.Server1Impl
运行Client1就会得到前面一样的结果。

最后要说明的是rmid(父进程)的系统参数会自动传给激活组对应的java子进程,比如rmid -J-Dcorp=lxj,我们可以在我们的服务类中通过
System.getProperties().getProperty("corp")取到。

<think>好的,我现在需要回答用户关于Linux消息队列的介绍。首先,我要确保自己理解这个主题,然后按照用户的要求结构清晰、分步骤说明。用户提到了系统级指令,比如使用正确的LaTeX格式,但这个问题可能不太涉及数学公式,不过还是需要注意是否有需要的地方。 首先,我应该回忆Linux消息队列的基本概念。消息队列是进程间通信(IPC)的一种方式,允许进程通过发送和接收消息来交换数据。接下来,可能需要介绍它的特点,比如异步通信、消息结构、内核持久性等。 然后,我需要考虑消息队列的工作原理,包括创建、发送、接收和删除消息队列的步骤。可能需要提到相关的系统调用,比如msgget、msgsnd、msgrcv、msgctl,这些属于System V IPC机制。或者用户可能想了解POSIX消息队列?这里可能需要区分一下,但通常Linux中常用的有System V和POSIX两种,不过用户没有特别说明,可能需要都提到或者选择主要的。 另外,需要指出消息队列的优点和缺点,比如与管道、共享内存等其他IPC方式的对比。例如,消息队列可以保存消息直到被读取,支持不同的数据类型,但可能有性能上的开销。 还要注意用户的结构要求,分步骤或分点介绍。可能需要组织成几个部分:定义、工作原理、使用步骤、相关API、优缺点、应用场景等。 同时,检查是否需要使用LaTeX。比如在说明消息结构时,如果有变量或公式,可能需要用行内公式,例如消息类型可能用$mtype$表示。但可能这类内容较少,但如果有的话要正确应用格式。 另外,用户要求用中文回答,所以需要确保术语准确,比如“消息队列”、“进程间通信”等。 现在,我需要确认自己是否遗漏了重要点。例如,消息队列的生命周期,是否随内核持续,需要显式删除。权限设置,比如msgget时的权限位。还有消息的格式,每个消息包含一个长整型的类型和实际数据。 可能还需要提到使用消息队列时需要注意的问题,比如系统资源限制,最大消息数、每个消息的大小限制等,这些可以通过sysctl配置。 然后,可能给出一个简单的例子,说明如何使用msgget、msgsnd等函数,但用户可能不需要代码示例,只是概念介绍。不过如果有的话,可以简要说明步骤。 最后,总结消息队列的适用场景,比如需要在进程间异步发送结构化数据的情况,或者需要根据消息类型选择性读取的情况。 需要确保内容真实可靠,比如正确引用系统调用和机制,不出现错误的信息。例如,System V消息队列和POSIX消息队列的区别:POSIX更现代,接口更简洁,但可能需要检查内核支持情况。不过通常介绍时可能以System V为主,因为比较经典。 现在组织内容结构: 1. 定义和作用:Linux消息队列是什么,用于进程间通信,存储消息的链表,每个消息有类型和数据。 2. 核心特性:异步通信、消息类型、内核持久性、访问控制。 3. 工作原理:创建、发送、接收、控制(msgget, msgsnd, msgrcv, msgctl)。 4. 消息结构:类型+数据,例如struct msgbuf。 5. 使用步骤:创建队列、发送消息、接收消息、删除队列。 6. 优缺点:对比管道、共享内存等,优势在于结构化和异步,缺点可能是性能开销和资源限制。 7. 应用场景:需要可靠通信、异步处理、多对多通信的情况。 在写作过程中,要避免技术性错误,比如正确说明系统调用的功能。例如,msgget用于创建或获取队列,msgsnd发送,msgrcv接收,msgctl用于控制(如删除)。 另外,检查是否需要提到权限和标识符,比如键值(key)用于标识消息队列,ftok函数生成key等。 可能还需要提到消息队列的局限性,比如在大量数据传输时效率不如共享内存,或者消息大小的限制。 最后,确保按照用户的格式要求,分点结构清晰,使用中文术语正确,没有使用Markdown格式,而是用自然分段和编号。</think>Linux消息队列是一种重要的进程间通信(IPC)机制,允许不同进程通过发送和接收结构化消息进行数据交换。以下从核心概念到应用场景分步骤介绍: --- ### 一、定义与作用 **消息队列**是内核维护的一个消息链表,进程可通过唯一标识符访问队列。每个消息包含: - **消息类型**(长整型,用$mtype$表示) - **消息正文**(用户自定义数据) 作用:解耦发送方和接收方,支持异步通信,适用于多进程协作场景。 --- ### 二、核心特性 1. **异步通信**:发送方和接收方无需同时运行。 2. **消息分类**:接收方可按$mtype$选择性读取消息。 3. **内核持久性**:消息在内核中存储,直到被读取或系统重启。 4. **访问控制**:通过权限位(如$0644$)限制队列访问。 --- ### 三、工作原理 Linux提供两组消息队列接口: 1. **System V消息队列** - 关键函数: - `msgget()`:创建/获取队列 - `msgsnd()`:发送消息 - `msgrcv()`:接收消息 - `msgctl()`:控制队列(如删除) - 标识符:通过`ftok()`生成唯一键值($key$)。 2. **POSIX消息队列** - 接口更简洁(如`mq_open()`, `mq_send()`)。 - 支持消息优先级和超时机制。 --- ### 四、使用步骤(以System V为例) 1. **创建队列** ```c int msgid = msgget(key, IPC_CREAT | 0666); ``` 2. **发送消息** 定义消息结构: ```c struct msgbuf { long mtype; char mtext[1024]; }; ``` 调用`msgsnd(msgid, &msg, sizeof(msg.mtext), 0);` 3. **接收消息** `msgrcv(msgid, &msg, sizeof(msg.mtext), mtype, 0);` 4. **删除队列** `msgctl(msgid, IPC_RMID, NULL);` --- ### 五、优缺点对比 | **优点** | **缺点** | |-----------------------------|-----------------------------| | 支持结构化数据 | 数据拷贝开销较大 | | 异步通信降低耦合度 | 存在系统级资源限制(队列数量、消息大小) | | 消息按类型过滤 | 需手动管理队列生命周期 | --- ### 六、应用场景 1. **任务分发系统**:主进程将任务封装为消息,多个工作进程按类型处理。 2. **日志收集**:多个进程发送日志到队列,日志服务异步读取。 3. **微服务通信**:解耦服务间的直接依赖,提升系统容错性。 --- ### 七、注意事项 - 及时清理未使用的队列(通过`ipcs -q`查看,`ipcrm`删除)。 - 避免消息过大(可通过`msgmax`内核参数调整,默认约$8KB$)。 - 优先考虑POSIX消息队列(若系统支持),因其设计更现代。 通过合理使用消息队列,可显著提升复杂系统中进程协作的灵活性与可靠性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值