RPC is remote procedure calls. Where RMI lets you interoperate directly with a Java object, RPC is built in more of a dispatch fashion. Instead of dealing with objects, RPC lets you use standalone methods across a network. Although this limits interactivity, it does make for a slightly simpler interface to the client. You can think of RPC as a way to use "services" on remote machines, while RMI allows you to use "servers" on remote machines. The subtle difference is that RMI typically is driven entirely by the client, with events occurring when methods are invoked remotely. RPC is often built more as a class or set of classes that works to perform tasks with or without client intervention; however, at times these classes service requests from clients, and execute "mini" tasks for the clients. I will show you some examples shortly to clarify these definitions.
RPC, while not as interactive an environment as RMI, does offer some significant advantages. RPC allows disparate systems to work together. While RMI allows the use of IIOP for connecting Java to CORBA servers and clients, RPC allows literally any type of application intercommunication, because the transport protocol can be HTTP. Since virtually every language in use today has some means of communicating via HTTP, RPC is very attractive for programs that must connect to legacy systems. RPC is also typically more lightweight than RMI (particularly when using XML as the encoding, which I'll cover next); while RMI often has to load entire Java classes over the network (such as code for applets and custom helper classes for EJB), RPC only has to pass across the request parameters and the resulting response, generally encoded as textual data. RPC also fits very nicely into the API model, allowing systems that are not part of your specific application to still access information from your application. This means that changes to your server do not have to result in changes to other clients' application code; with pure textual data transfer and requests, additional methods can be added without client recompilation, and minor changes are sufficient to use these new methods.
The problem with RPC has traditionally been the encoding of data in transfer; imagine trying to represent a Java Hashtable or Vector in a very lightweight way through textual formats. When you consider that these structures can, in turn, hold other Java object types, the data representation quickly becomes tricky to write; it also has to remain a format that is usable by all the disparate programming languages, or the advantages of RPC are lessened. Until recently, an inverse relationship had been developing between the quality and usability of the encoding and its simplicity; in other words, the easier it became to represent complex objects, the more difficult it became to use the encoding in multiple programming languages without proprietary extensions and code. Elaborate textual representations of data were not standardized and required completely new implementations in every language to be usable. You can see where this discussion is leading.
Learn about What is RMI?
Learn about What is RMI?