1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
|
<title>RPC</title>
<body bgcolor="#ffffcc">
<hr>
<center><h1>Remote Procedure Calls (RPC).</h1></center>
<hr>
In the normal scope of things, a program can only call a function
that is linked into the executable or provided by a shared library.
RPC allows programs to execute functions in another executing program, cool!
<p>
RPC has a concept of clients and servers.
<ol>
<li>The client issues requests to the server.
<li>Servers perform the requests and return the results.
<li>The data that flows between client and server includes
int, float, strings and structures.
<li>The client and server can be on the same host or different hosts
connected via a network.
<li>The hosts do not have to be the same artitechture.
</ol>
The RPC <a href=../glossary.html#api>API</a> has three levels of support.
By using the highest level
RPC is responcable for most of the code but is not too flexable. The lowest
level requres more coding but gives the programmer more control over how RPC
functions.
<p>
The easiest way to start with RPC is to use a program called <b>rpcgen</b>
this reads a file that describes the required interface between client and server
and generates C code that you can include in your client and server.
<pre>
prog.x --> rpcgen ---> prog.h Header file
---> prog_clnt.c Client stubs file
---> prog_svc.c Server stubs file
---> prog_xdr.c XDR routines (more later).
</pre>
You write <b>prog.x</b> and rpcgen generates
<b>prog.h prog_clnt.c prog_svc.c prog_xdr.c</b>
You then write the client and server and link them with the rpcgen code
to complete the RPC system.
<pre>
client.c -----> client executable
prog.h ---|
prog_clnt.c ---|
prog_xdr.c ---|
server.c -----> Server executable
prog.h ---|
prog_svc.c ---|
prog_xdr.c ---|
</pre>
Ok, time for some examples.
<h3>Calling an RPC server function without passing any arguments.</h3>
This is the simplest form of RPC.
<p>
<center>
<table bgcolor=ivory width=80%>
<th>
void.x
</th>
<tr>
<td>
<pre>
/* RPCGEN code decribing the client/server API. */
program MJLPROG
{
version MJLVERS
{
void VOID(void) = 1;
} = 1;
} = 0x20000001;
</pre>
</td>
</tr>
</table>
</center>
<p>
<b>void.x</b> describes the RPC interface between the client
and server. There are some important items to note here.
<p>
<table><tr>
<td bgcolor=silver>
<pre>
program MJLPROG
{
} = 0x20000001;
</pre></td>
<td>This is the RPC program number. It is used by the client to
identify the server it intends to use.
It is important that you provide a unique number here. You can see
which values are in use with the Unix command <b>rpcinfo -p</b> or
by looking at <b>/etc/rpc</b>. Please note that the number is supplied
in void.x as a hex value but shown as a decimal value by <b>rpcinfo</b>
One other point, you should only use values in the range 0x20000000
0x3FFFFFFF as these have been reserved for use local use.
</td>
</tr>
<tr>
<td bgcolor=silver>
<pre>
version MJLVERS
{
} = 1;
</pre></td>
<td>The RPC Version number.</td>
</tr>
<tr>
<td bgcolor=silver><pre>void VOID(void) = 1;</pre></td>
<td>This defines the only RPC function that the server will provide.</td>
</tr>
</table>
<p>
<center>
<table bgcolor=ivory width=80%>
<th>
void_client.c
</th>
<tr>
<td>
<pre>
#include <rpc/rpc.h>
#include "void.h"
main()
{
CLIENT *pclnt;
void *pVoid;
char Host[256];
/* Get the name of the host running the server. */
gethostname(Host, 256);
/* Connect to the server. */
pclnt = clnt_create(Host, MJLPROG, MJLVERS, "udp");
/* Issue a request to the server. */
void_1(pVoid, pclnt);
/* Disconnect from the server. */
clnt_destroy(pclnt);
}
</pre>
</td>
</tr>
</table>
</center>
<p>
<table>
<tr>
<td bgcolor=silver>
<pre>
#include <rpc/rpc.h>
</pre>
</td>
<td>
Include the standard RPC headers.
</td>
</tr>
<tr>
<td bgcolor=silver>
<pre>
#include "void.h"
</pre>
</td>
<td>
Include the header file generated by <b>rpcgen</b>
</td>
</tr>
<tr>
<td bgcolor=silver>
<pre>
pclnt = clnt_create();
</pre>
</td>
<td>Connect to the server <b>MJLPROG</b> on <b>Host</b> and return a
pointer to the <b>CLIENT</b> control structure.
</td>
</tr>
<tr>
<td bgcolor=silver>
<pre>
void_1(pVoid, pclnt);
</pre>
</td>
<td>
Call the remote function.
</td>
</tr>
<tr>
<td bgcolor=silver>
<pre>
clnt_destroy();
</pre>
</td>
<td>
Disconnect from the server.
</td>
</tr>
</table>
<p>
<center>
<table bgcolor=ivory width=80%>
<th>
void_server.c
</th>
<tr>
<td>
<pre>
#include <rpc/rpc.h>
#include "void.h"
void *void_1_svc(void *pVoid, struct svc_req *X)
{
printf("Function called without passing arguments\n");
}
</pre>
</td>
</tr>
</table>
</center>
<p>
<table>
<tr>
<td bgcolor=silver>
<pre>
void *void_1_svc()
</pre>
</td>
<td>
The server function that will be run for the client.
</td>
</tr>
</table>
<p>
Please note that the server does not have a <b>main()</b>, rpcgen
generates it for you.
<p>
The code can be compiled with the following commands
<pre>
gcc void_server.c void_svc.c -o void_server
gcc void_client.c void_clnt.c -o void_client
</pre>
<p>
In theory you should be able to start the server and it will
respond everytime the client is executed. I have not included any
error recovery into this example as it makes the code harder to
read. As an exercise try adding the error recovery code yourself :-)
<h3>Transfer integers between the client and server</h3>
<p>
<center>
<table bgcolor=ivory width=80%>
<th>
integer.x
</th>
<tr>
<td>
<pre>
/* RPCGEN code decribing the client/server API. */
program MJLPROG
{
version MJLVERS
{
int INTEGER(int) = 1;
} = 1;
} = 0x20000001;
</pre>
</td>
</tr>
</table>
</center>
<p>
<table>
<tr>
<td bgcolor=silver>
<pre>
int INTEGER(int) = 1;
</pre>
</td>
<td>
Server function now accepts an integer and returns an integer.
</td>
</tr>
</table>
<p>
<hr>
<h2>See Also:</h2>
<img src=../../GRAPHICS/whiteball.gif>
<a href=../SYNTAX/void.html>VOID keyword.</a>
<hr>
<p>
<center>
<table border=2 width=80% bgcolor=ivory>
<tr align=center>
<td width=25%>
<a href=../cref.html>Top</a>
</td><td width=25%>
<a href=../master_index.html>Master Index</a>
</td><td width=25%>
<a href=../SYNTAX/keywords.html>Keywords</a>
</td><td width=25%>
<a href="../FUNCTIONS/funcref.htm">Functions</a>
</td>
</tr>
</table>
</center>
<p>
<hr>
29-Dec-97
<address>Martin Leslie
|