Monday, November 14, 2005


Multithreaded RPC Server in White Box Linux 3 environment



This can be considered an example, as shown in reference [1] chapter "Sun RPC".
This is the file square_svc.c for file square.x to build a multithreaded
RPC Server for White Box Linux 3.File square.x (as in reference [1]):


struct square_in {
long arg1;
};
struct square_out {
long res1;
};
program SQUARE_PROG {
version SQUARE_VERS {
square_out SQUAREPROC(square_in) = 1;
} = 2 ;
} = 0x31230000;




Call rpcgen to generate servers, client stubs, header file square.h
and square_xdr.c. Remember key -A is not supported under Linux.
That is why we have an issue (compare with SunOS).


$ rpcgen –a –M square.x




Server's side procedures code:



/*
* ServerSideProc.c
*/
#include "square.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>

int request=0;

bool_t

squareproc_2_svc(square_in *inp,square_out *outp,struct svc_req *rqstp)
{
printf("Thread id = '%ld' started, arg = %d\n",pthread_self(),inp->arg1);
sleep(5);
outp->res1=inp->arg1*inp->arg1;
printf("Thread id = '%ld' is done %d \n",pthread_self(),outp->res1);
return(TRUE);
}
int
square_prog_2_freeresult(SVCXPRT *transp,xdrproc_t xdr_result,
caddr_t result)
{
xdr_free(xdr_result,result);
return(1);
}




Modified code square_svc.c:


/* square_svc.c
*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "square.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif

struct thr_data
{
struct svc_req *rqstp;
SVCXPRT *transp;
} ;

pthread_t p_thread;
pthread_attr_t attr;
/* Procedure to be run by thread */

void *
serv_request(void *data)
{
struct thr_data *ptr_data = (struct thr_data *)data;
{
union {
square_in squareproc_2_arg;
} argument;
union {
square_out squareproc_2_res;
} result;
bool_t retval;
xdrproc_t _xdr_argument, _xdr_result;
bool_t (*local)(char *, void *, struct svc_req *);
struct svc_req *rqstp = ptr_data->rqstp;
register SVCXPRT *transp = ptr_data->transp;
switch (rqstp->rq_proc) {
case NULLPROC:
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case SQUAREPROC:
_xdr_argument = (xdrproc_t) xdr_square_in;
_xdr_result = (xdrproc_t) xdr_square_out;
local = (bool_t (*) (char *, void *, struct svc_req *))squareproc_2_svc;
break;
default:
svcerr_noproc (transp);
return;
}
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
svcerr_decode (transp);
return;
}
retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);
if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result))
{
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
if (!square_prog_2_freeresult (transp, _xdr_result, (caddr_t) &result))
fprintf (stderr, "%s", "unable to free results");
return;
}
}
/*
New code for square_prog_2
*/
static void
square_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
struct data_str
{
struct svc_req *rqstp;
SVCXPRT *transp;
} *data_ptr=(struct data_str*)malloc(sizeof(struct data_str));
{
data_ptr->rqstp = rqstp;
data_ptr->transp = transp;
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
pthread_create(&p_thread,&attr,serv_request,(void *)data_ptr);
}
}
int
main (int argc, char **argv)
{
register SVCXPRT *transp;
pmap_unset (SQUARE_PROG, SQUARE_VERS);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, SQUARE_PROG, SQUARE_VERS, square_prog_2, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (SQUARE_PROG, SQUARE_VERS, udp).");
exit(1);
}
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create tcp service.");
exit(1);
}
if (!svc_register(transp, SQUARE_PROG, SQUARE_VERS, square_prog_2, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (SQUARE_PROG, SQUARE_VERS, tcp).");
exit(1);
}
svc_run ();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
/* NOTREACHED */
}





Compile ServerSQUARE:


$ gcc –o ServerSQUARE ServerSideProc.c square_svc.c square_xdr.c –lprthread -lnsl




Client's side code:


/*
* ClientSideProc.c
*/

#include "memory.h" /* for memset */
#include "square.h"
#include "stdio.h"
#include "stdlib.h"
#include "rpc/pmap_clnt.h"
#include "string.h"
#include "memory.h"
#include "sys/socket.h"
#include "netinet/in.h"

int
main (int argc,char **argv)
{
CLIENT *cl;
square_in in;
square_out out;
if (argc != 3 )
{ printf ("Usage : client "hostname" "integer_valus=e"\n");
exit(1);
}
cl = clnt_create(argv[1],SQUARE_PROG,SQUARE_VERS,"tcp");
if (cl == NULL) {
clnt_perror (cl, "call failed");
exit (1);
}
in.arg1 = atol(argv[2]);
if (squareproc_2(&in,&out,cl) != RPC_SUCCESS)
{
printf (“%s\n” , clnt_perror (cl,argv[1] ));
exit(1);
}
printf("result: %ld\n",out.res1);
exit(0);
}




Now compile ClientSQUARE:


$ gcc –o ClientSQUARE ClientSideProc.c square_clnt.c square_xdr.c -lprthread -lnsl




Testing (see [1], chapter “SUN RPC”):

[root@dell4500 SQWMT]# cat square.bsh

./ClientSQUARE dell4500.redhat 10 & ./ClientSQUARE dell4500.redhat 11 & ./ClientSQUARE dell4500.redhat 12 & ./ClientSQUARE dell4500.redhat 21 & ./ClientSQUARE dell4500.redhat 13 & ./ClientSQUARE dell4500.redhat 14 & ./ClientSQUARE dell4500.redhat 15 & ./ClientSQUARE dell4500.redhat 16 & ./ClientSQUARE dell4500.redhat 17 & ./ClientSQUARE dell4500.redhat 18 & ./ClientSQUARE dell4500.redhat 19 & ./ClientSQUARE dell4500.redhat 20 &




Output on client's side:


[root@dell4500 SQWMT]# ./square.bsh
[root@dell4500 SQWMT]# result: 196
result: 225
result: 256
result: 289
result: 121
result: 144
result: 441
result: 169
result: 100
result: 324
result: 361
result: 400




Output on Server's side:


[root@dell4501 SQWMT]# ./ServerSQUARE
Thread id = '1082453184' started, arg = 14
Thread id = '1090841664' started, arg = 15
Thread id = '1099230144' started, arg = 16
Thread id = '1116941120' started, arg = 17
Thread id = '1125329600' started, arg = 11
Thread id = '1133718080' started, arg = 12
Thread id = '1142106560' started, arg = 21
Thread id = '1150495040' started, arg = 13
Thread id = '1158883520' started, arg = 10
Thread id = '1167272000' started, arg = 18
Thread id = '1175660480' started, arg = 19
Thread id = '1184048960' started, arg = 20
Thread id = '1082453184' is done 196
Thread id = '1090841664' is done 225
Thread id = '1099230144' is done 256
Thread id = '1116941120' is done 289
Thread id = '1125329600' is done 121
Thread id = '1133718080' is done 144
Thread id = '1142106560' is done 441
Thread id = '1150495040' is done 169
Thread id = '1158883520' is done 100
Thread id = '1167272000' is done 324
Thread id = '1175660480' is done 361
Thread id = '1184048960' is done 400





References:

1. W. Richard Stevens UNIX: Network Programming v 2.Interprocess communications,
Prentice Hall,1999