Category Archives: Laboratory Work

PRACTICAL 4: Write a program to find average of given numbers using rpcgen command.

third.x

struct average

{

int a[10];

int n;

};

program third

{

version ver

{

int ave(average)=1;

}=1;

}=0x36767676;

 

third_client.c

/* This is sample code generated by rpcgen. These are only templates and you can use them

as a guideline for developing your own functions.

*/

 

#include “third.h”

#include “third_clnt.c”

 

void

third_1(char *host)

{

CLIENT *clnt;

int *result_1,i;

average ave_1_arg;

 

printf(“Enter Value:\n”);

scanf(“%d”,&ave_1_arg.n);

 

for(i=0;i<ave_1_arg.n;i++)

{

printf(“Enter Value%d:\n”,i+1);

scanf(“%d”,&ave_1_arg.a[i]);

}

 

#ifndef DEBUG

clnt = clnt_create (host, third, ver, “udp”);

if (clnt == NULL) {

clnt_pcreateerror (host);

exit (1);

}

#endif /* DEBUG */

 

result_1 = ave_1(&ave_1_arg, clnt);

printf(“Average is %d\n”,*result_1);

 

if (result_1 == (int *) NULL) {

clnt_perror (clnt, “call failed”);

}

#ifndef DEBUG

clnt_destroy (clnt);

#endif   /* DEBUG */

}

 

 

int

main (int argc, char *argv[])

{

char *host;

 

if (argc < 2) {

printf (“usage: %s server_host\n”, argv[0]);

exit (1);

}

host = argv[1];

third_1 (host);

exit (0);

}

 

third_server.c

 

/* This is sample code generated by rpcgen. These are only templates and you can use them

as a guideline for developing your own functions.

*/

 

#include “third.h”

#include “third_svc.c”

int *

ave_1_svc(average *argp, struct svc_req *rqstp)

{

static int result;

int sum=0,i;

 

for (i=0;i<((*argp).n);i++)

{

sum=sum+(*argp).a[i];

}

 

result=sum/(*argp).n;

printf(“Average is %d\n”,result);

return &result;

}

 

 

third_xdr.c

 

/* Please do not edit this file. It was generated using rpcgen. */

#include “third.h”

bool_t

xdr_average (XDR *xdrs, average *objp)

{

register int32_t *buf;

int i;

if (xdrs->x_op == XDR_ENCODE) {

buf = XDR_INLINE (xdrs, (1 + 10 )* BYTES_PER_XDR_UNIT);

if (buf == NULL) {

if (!xdr_vector (xdrs, (char *)objp->a, 10,

sizeof (int), (xdrproc_t) xdr_int))

return FALSE;

if (!xdr_int (xdrs, &objp->n))

return FALSE;

} else {

{

register int *genp;

for (i = 0, genp = objp->a;

i < 10; ++i) {

IXDR_PUT_LONG(buf, *genp++);

}

}

IXDR_PUT_LONG(buf, objp->n);

}

return TRUE;

} else if (xdrs->x_op == XDR_DECODE) {

buf = XDR_INLINE (xdrs, (1 + 10 )* BYTES_PER_XDR_UNIT);

if (buf == NULL) {

if (!xdr_vector (xdrs, (char *)objp->a, 10,

sizeof (int), (xdrproc_t) xdr_int))

return FALSE;

if (!xdr_int (xdrs, &objp->n))

return FALSE;

} else {

{

register int *genp;

for (i = 0, genp = objp->a; i < 10; ++i)

{ *genp++ = IXDR_GET_LONG(buf);}

}

objp->n = IXDR_GET_LONG(buf);

}

return TRUE;

}

if (!xdr_vector (xdrs, (char *)objp->a, 10,

sizeof (int), (xdrproc_t) xdr_int))

return FALSE;

if (!xdr_int (xdrs, &objp->n))

return FALSE;

return TRUE;

}

Practical 3: Write a program to add two given numbers at server side using rpcgen command.

second.x

struct add

{

int a;

int b;

};

program second

{

version ver

{

int sum(add)=1;

}=1;

}=0x33000000;

second_client.c

/* This is sample code generated by rpcgen. These are only templates and you can

use them as a guideline for developing your own functions. */

#include “second.h”

#include “second_clnt.c”  // *** first modification ***********

void

second_1(char *host)

{

CLIENT *clnt;

int *result_1;

add sum_1_arg;

printf(“Enter Two Numbers\n”);   // *** second modification ***********

scanf(“%d%d”, &sum_1_arg.a, &sum_1_arg.b);

#ifndef DEBUG

clnt = clnt_create (host, second, ver, “udp”);

if (clnt == NULL) {

clnt_pcreateerror (host);

exit (1);

}

#endif /* DEBUG */

result_1 = sum_1(&sum_1_arg, clnt);

if (result_1 == (int *) NULL) {

clnt_perror (clnt, “call failed”);

}

#ifndef DEBUG

clnt_destroy (clnt);

#endif /* DEBUG */

}

int

main (int argc, char *argv[])

{

char *host;

if (argc < 2) {

printf (“usage: %s server_host\n”, argv[0]);

exit (1);

}

host = argv[1];

second_1 (host);

exit (0);

}

second_server.c

/* This is sample code generated by rpcgen. These are only templates and you can

use them as a guideline for developing your own functions. */

#include “second.h”

#include “second_svc.c”

int * sum_1_svc(add *argp, struct svc_req *rqstp)

{

static int result;

result=(*argp).a+(*argp).b;

printf(“Addition=%d\n”,result);

return &result;

}

Practical 2: Write a program to convert given digit into appropriate word using rpcgen command.

first.x

program first

{
version vers
{

int dtow(int)=1;

}=1;

}=0x35656565;

 

Steps:

  1. Compile it using above command: rpcgen –a first.x
  2. It will create more six files in the same folder named, (1) first_client.c (2) first_clnt.c (3) first_server.c (4) first_svc.c (5) first.h and (6) Makefile.first

 

***************************************************************

first_client.c

/*

* This is sample code generated by rpcgen.

* These are only templates and you can use them

* as a guideline for developing your own functions.

*/

 

#include “first.h”

#include “first_clnt.c”             //**** First Modification ****//

 

void

first_1(char *host)

{

CLIENT *clnt;

int *result_1;

int dtow_1_arg;

 

//**** Second Modification ****//

printf(“Enter any No to convert it from Digit to Word:\n”);

scanf(“%d”,&dtow_1_arg);

 

#ifndef DEBUG

clnt = clnt_create (host, first, vers, “udp”);

if (clnt == NULL) {

clnt_pcreateerror (host);

exit (1);

}

#endif /* DEBUG */

 

result_1 = dtow_1(&dtow_1_arg, clnt);

 

//**** Third Modification ****//

printf(“Result received from Server is:%d\n”,*result_1);

 

if (result_1 == (int *) NULL) {

clnt_perror (clnt, “call failed”);

}

#ifndef DEBUG

clnt_destroy (clnt);

#endif   /* DEBUG */

}

 

 

int

main (int argc, char *argv[])

{

char *host;

 

if (argc < 2) {

printf (“usage: %s server_host\n”, argv[0]);

exit (1);

}

host = argv[1];

first_1 (host);

exit (0);

}

 

Now compile above program using command: gcc –o fc first_client.c

*****************************************************************

first_server.c

 /*

* This is sample code generated by rpcgen.

* These are only templates and you can use them

* as a guideline for developing your own functions.

*/

 

#include “first.h”

#include “first_svc.c”

 

int *

dtow_1_svc(int *argp, struct svc_req *rqstp)

{

static int result;

 

if(*argp==0)

printf(“ZERO\n”);

else if(*argp==1)

printf(“ONE\n”);

else if(*argp==2)

printf(“TWO\n”);

else if(*argp==3)

printf(“THREE\n”);

else if(*argp==4)

printf(“FOUR\n”);

else if(*argp==5)

printf(“FIVE\n”);

else if(*argp==6)

printf(“SIX\n”);

else if(*argp==7)

printf(“SEVEN\n”);

else if(*argp==8)

printf(“EIGHT\n”);

else if(*argp==9)

printf(“NINE\n”);

else

printf(“Not Known\n”);

 

result=(*argp)+10;

 

return &result;

}

 

Now compile above program using command: gcc –o fs first_server.c

Then run the program using command: ./fs

It will start server running.

 

********************************************************************

Now start another instance of telnet and run the client program using command:

./fc server-host [give the name where user is logged on]

PRACTICAL 1: Communications Programming Concepts

Remote Procedure Call

Remote Procedure Call (RPC) is a protocol that provides the high-level communications paradigm used in the operating system. RPC presumes the existence of a low-level transport protocol, such as Transmission Control Protocol/Internet Protocol (TCP/IP) or User Datagram Protocol (UDP), for carrying the message data between communicating programs. RPC implements a logical client-to-server communications system designed specifically for the support of network applications.

 

RPC Model

A client is a computer or process that accesses the services or resources of another process or computer on the network. A server is a computer that provides services and resources, and that implements network services. Each network service is a collection of remote programs. A remote program implements remote procedures. The procedures, their parameters, and the results are all documented in the specific program’s protocol.

Remote Procedure Call Flow: This diagram shows the client process on the left which contains (listed from top to bottom) the client, client stub, RPC run-time library. The server process on the right contains the following (listed from top to bottom): manager procedures, server stub, and the RPC run-time library. The calls can go from the client to the manager procedures crossing the apparent flow and above the interface. The call from the client can also go through the interface to the client stub. From the client stub, the call can travel to the RPC run-time library in the client process. The call can travel to the library in the server process as a network message. Calls in the server process can go from the RPC run-time library to the server stub and from the server stub to the manager procedures. Note that there is a return in the opposite direction of each call mentioned.
DS

In the RPC model, only one of the two processes is active at any given time. Furthermore, this model is only an example. The RPC protocol makes no restrictions on the concurrency model implemented, and others are possible. For example, an implementation can choose asynchronous Remote Procedure Calls so that the client can continue working while waiting for a reply from the server. Additionally, the server can create a task to process incoming requests and thereby remain free to receive other requests.

Programming in RPC

Remote procedure calls can be made from any language. Remote Procedure Call (RPC) protocol is generally used to communicate between processes on different workstations. However, RPC works just as well for communication between different processes on the same workstation.

The RPC interface can be seen as being divided into three layers: highest, intermediate, and lowest. The highest layer of RPC is totally transparent to the operating system, workstation, and network on which it runs. This level is actually a method for using RPC routines, rather than a part of RPC proper.

The intermediate layer is RPC proper. At the intermediate layer, the programmer need not consider details about sockets or other low-level implementation mechanisms. The programmer makes remote procedure calls to routines on other workstations.

The lowest layer of RPC allows the programmer greatest control. Programs written at this level can be more efficient.

Both intermediate and lower-level RPC programming entail assigning program numbers, version numbers, and procedure numbers.

Assigning Program Numbers

A central system authority administers the program number (prog parameter). A program number permits the implementation of a remote program. The first implementation of a program is usually version number 1.

A program number is assigned by groups of 0x20000000 (decimal 536870912), according to the following list:

0-1xxxxxxx This group of numbers is predefined and administered by the operating system. The numbers should be identical for all system customers.
20000000-3xxxxxxx The user defines this group of numbers. The numbers are used for new applications and for debugging new programs.
40000000-5xxxxxxx This group of numbers is transient and is used for applications that generate program numbers dynamically.

All other are Reserved.

Assigning Version Numbers

Most new protocols evolve into more efficient, stable, and mature protocols. As a program evolves, a new version number (vers parameter) is assigned. The version number identifies which version of the protocol the caller is using. The first implementation of a remote program is usually designated as version number 1 (or a similar form).

Assigning Procedure Numbers

The procedure number (proc parameter) identifies the procedure to be called. The procedure number is documented in each program’s protocol specification. For example, a file service protocol specification can list the read procedure as procedure 5 and the write procedure as procedure 12.

rpcgen Protocol Compiler

The rpcgen protocol compiler accepts a remote program interface definition written in the Remote Procedure Call language (RPCL), which is similar to the C language. The rpcgen compiler helps programmers write RPC applications in a simple and direct manner. The rpcgen compiler debugs the network interface code, thereby allowing programmers to spend their time debugging the main features of their applications.

The rpcgen compiler produces a C language output that includes the following:

  • Stub versions of the client and server routines
  • Server skeleton
  • eXternal Data Representation (XDR) filter routines for parameters and results
  • A header file that contains common definitions of constants and macros

Client stubs interface with the RPC library to effectively hide the network from its callers. Server stubs similarly hide the network from server procedures invoked by remote clients. The rpcgen output files can be compiled and linked in the usual way. Using any language, programmers write server procedures and link them with the server skeleton to get an executable server program.

 

RPCGEN Command Basics

usage: rpcgen infile

rpcgen [-abkCLNTM][-Dname[=value]] [-i size] [-I [-K seconds]] [-Y path] infile

rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm] [-o outfile] [infile]

rpcgen [-s nettype]* [-o outfile] [infile]

rpcgen [-n netid]* [-o outfile] [infile]

options:

-a             generate all files, including samples

-b             backward compatibility mode (generates code for SunOS 4.1)

-c             generate XDR routines

-C             ANSI C mode

-Dname[=value] define a symbol (same as #define)

-h             generate header file

-i size       size at which to start generating inline code

-I             generate code for inetd support in server (for SunOS 4.1)

-K seconds     server exits after K seconds of inactivity

-l             generate client side stubs

-L             server errors will be printed to syslog

-m           generate server side stubs

-M           generate MT-safe code

-n netid      generate server code that supports named netid

-N             supports multiple arguments and call-by-value

-o outfile     name of the output file

-s nettype     generate server code that supports named nettype

 

For our practical we will use command:

[root@server-host ~] rpcgen –a filename.x