from [1] Chapter "RPC". Actually code published in [1] utilizes static
variables what causes question 23.10 from [1](about multihreaded
implementation of RPC Server under Linux) to produce some confusion.
Originally only two files are taken from [1]: rdict.x and rdict_srp.c. All
business logic is implemented into rdict_client.c - file generated by
command:
$ rpcgen -a -M rdict.x
Files rdict.c and rdict_cif.c (see [1] , Chapter "RPC") are taken out to
highlight the core of RPC technology either "Sun" or "DCE"
Remember -A option of rpcgen is not supported under Linux. Library calls
providing by SunOS RPC to build Multithreaded RPC Server are unavailable under Linux as well.
I believe that code has been developed could be very helpful for Linux developers at this time.
The example given bellow demonstrate the universal approach to build multithreaded RPC Severs
for Linux.
Source of rdict.x:
const MAXWORD=50; const DICTSIZ=100; struct example{ int exfield1; char exfield2; }; program RDICTPROG { version RDICTVERS { int INITW(void)=1; int INSERTW(string)=2; int DELETEW(string)=3; int LOOKUPW(string)=4; } =1; } =0x30090949;
Source of rdict_srp.c :
#include <rpc/rpc.h> #include <string.h> #include "rdict.h" char dict[DICTSIZ][MAXWORD+1]; static char snd[50]; static int lns; int nwords=0; int initw() { nwords=0; return 1; } int insertw(char *word) { strcpy(dict[nwords],word); nwords++; return nwords; } int deletew(char *word) { int i; for(i=0;i < nwords;i++) if(strcmp(word,dict[i])==0) { nwords--; strcpy(dict[i],dict[nwords]); return 1; } return 0; } int lookupw(char *word) { int i; for(i=0;i<nwords;i++) if(strcmp(word,dict[i])==0) return 1; return 0; } rdictprog_1_freeresult(SVCXPRT *transp,xdrproc_t xdr_result, caddr_t result) { xdr_free(xdr_result,result); return(1); }
Call rpcgen to generate stubs ,header file rdict.h and rdict_xdr:
$rpcgen -a -M rdict.x
Modified files on server's side follows bellow:
File rdict_sif.c contains thread-safe code instead of utilizing static variables
for to return results to client.
/* * rdict_sif.c (compare with file rdict_sif.c in [1] chapter "RPC") */ #include <rpc/rpc.h> #define RPC_SVC #include "rdict.h"
int initw(void),insertw(char *),deletew(char *),lookupw(char *); bool_t insertw_1_svc(char **w,int *ptr_retcode,struct svc_req *rqstp) { *ptr_retcode=insertw(*(char **)w); return(TRUE); } bool_t initw_1_svc(void *w,int *ptr_retcode,struct svc_req *rqstp) { *ptr_retcode=initw(); return(TRUE); } bool_t deletew_1_svc(char **w,int *ptr_retcode,struct svc_req *rqstp) { *ptr_retcode=deletew(*(char **)w); return(TRUE); } bool_t lookupw_1_svc(char **w,int *ptr_retcode,struct svc_req *rqstp) { *ptr_retcode=lookupw(*(char **)w); return(TRUE); }
Modified server's stub is file rdict_svc.c . Multithreaded version
/* Modified rdict_svc.c * * Please do not edit this file. * It was generated using rpcgen. */
#include "rdict.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 pthread_t p_thread; pthread_attr_t attr;
/* Procedure to be run by thread */
void * serv_request(void *data) { struct thr_data { struct svc_req *rqstp; SVCXPRT *transp; } *ptr_data; union { char *insertw_1_arg; char *deletew_1_arg; char *lookupw_1_arg; char *showupw_1_arg; char *getlenw_1_arg; } argument; union { int initw_1_res; int insertw_1_res; int deletew_1_res; int lookupw_1_res; char showupw_1_res; int getlenw_1_res; } result; bool_t retval; xdrproc_t _xdr_argument, _xdr_result; bool_t (*local)(char *, void *, struct svc_req *);
ptr_data = (struct thr_data *)data; 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 INITW: _xdr_argument = (xdrproc_t) xdr_void; _xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))initw_1_svc; break;
case INSERTW: _xdr_argument = (xdrproc_t) xdr_wrapstring; _xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))insertw_1_svc; break;
case DELETEW: _xdr_argument = (xdrproc_t) xdr_wrapstring; _xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))deletew_1_svc; break;
case LOOKUPW:
_xdr_argument = (xdrproc_t) xdr_wrapstring;
_xdr_result = (xdrproc_t) xdr_int;
local = (bool_t (*) (char *, void *, struct svc_req *))lookupw_1_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 (!rdictprog_1_freeresult (transp, _xdr_result, (caddr_t) &result))
fprintf (stderr, "%s", "unable to free results");
return; }
/* New code for procedure rdictprog_1 , starting thread in response for each clients request to invoke remote procedure */
static void rdictprog_1(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 (RDICTPROG, RDICTVERS);
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf (stderr, "%s", "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, RDICTPROG, RDICTVERS, rdictprog_1, IPPROTO_UDP)) {
fprintf (stderr, "%s", "unable to register (RDICTPROG, RDICTVERS, 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, RDICTPROG, RDICTVERS, rdictprog_1, IPPROTO_TCP)) {
fprintf (stderr, "%s", "unable to register (RDICTPROG, RDICTVERS, tcp).");
exit(1);
}
svc_run (); fprintf (stderr, "%s", "svc_run returned"); exit (1); /* NOTREACHED */ }
Compile server:
$ gcc -o ServerDT rdict_svc.c rdict_sif.c rdict_srp.c rdict_xdr.c -lpthread -lnsl
Modified code of rdict_client.c with implemented business logic. Template has been already generated by "rpcgen -a -M rdict.x"
/* File rdict_client.c versus rdict.c&rdict_cif from [1] chapter "RPC" * * 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 "rdict.h" #define MAXWORD 50
char buf[80]; void rdictprog_1(char *host) { CLIENT *clnt; enum clnt_stat retval_1; int result_1; char *initw_1_arg="0"; enum clnt_stat retval_2; int result_2; char * insertw_1_arg; enum clnt_stat retval_3; int result_3; char * deletew_1_arg; enum clnt_stat retval_4; int result_4; char * lookupw_1_arg; int ch; char cmd; char word[MAXWORD+1]; int wrdlen;
#ifndef DEBUG clnt = clnt_create (host, RDICTPROG, RDICTVERS, "udp"); if (clnt == NULL) { clnt_pcreateerror (host); exit (1); } #endif /* DEBUG */ while(1) { wrdlen=nextin(&cmd,word); if(wrdlen < 0) exit(0); word[wrdlen]='\0'; switch(buf[0]) { case 'I': retval_1 = initw_1((void*)&initw_1_arg, &result_1, clnt); if (retval_1 != RPC_SUCCESS) { clnt_perror (clnt, "call failed"); } if (result_1 == 1) printf("Dictionary was initialized \n"); else printf("Dictionary failed to initialize \n"); break; case 'i': insertw_1_arg=word; retval_2 = insertw_1(&insertw_1_arg, &result_2, clnt); if (retval_2 != RPC_SUCCESS) { clnt_perror (clnt, "call failed"); } if (result_2 > 0 ) printf("Insert was done\n"); else printf("Insert failed\n"); break; case 'd': deletew_1_arg=word; retval_3 = deletew_1(&deletew_1_arg, &result_3, clnt); if (retval_3 != RPC_SUCCESS) { clnt_perror (clnt, "call failed"); } if (result_3 == 1 ) printf("Delete was done\n"); else printf("Delete failed\n"); break; case 'l': lookupw_1_arg=word; retval_4 = lookupw_1(&lookupw_1_arg, &result_4, clnt); if (retval_4 != RPC_SUCCESS) { clnt_perror (clnt, "call failed"); } if (result_4 == 1) printf("Word '%s' was found\n",word); else printf("Word '%s' was not found\n",word); break; case 'q': printf("Programm quits \n"); exit(0); default: printf("Command invalid\n"); break; } } #ifndef DEBUG clnt_destroy (clnt); #endif /* DEBUG */ } int nextin(char *cmd,char *word) { int i,ch; printf("\n"); printf("***** Make a choice ******\n"); printf("1. I(initialize dictionary)\n"); printf("2. i(inserting word) \n"); printf("3. l(looking for word)\n"); printf("4. d(deleting word)\n"); printf("5. q(quit)\n"); printf("***************************\n"); printf("Command prompt => \t"); ch=getc(stdin); while(isspace(ch)) ch=getc(stdin); if(ch==EOF) return -1; *cmd=(char)ch; sprintf(buf,"%s",cmd); if(buf[0] == 'q' || buf[0] == 'I') return 0; printf("*****************\n"); printf("Analysing Command\n"); printf("*****************\n"); if(buf[0]=='i' || buf[0]=='l'|| buf[0]=='d') { printf("Input word => \t"); } else { return 0; } ch=getc(stdin); while(isspace(ch)) ch=getc(stdin); if(ch==EOF) return -1; if(ch=='\n') return 0; i=0; while(!isspace(ch)) { if(++i> MAXWORD) { printf("Error word to long.\n"); exit(1); } *word++=ch; ch=getc(stdin); } return i; } int main (int argc, char *argv[]) { char *host;
if (argc < 2) { printf ("usage: %s server_host\n", argv[0]); exit (1); } host = argv[1]; rdictprog_1 (host); exit (0); }
Compile client:
$ gcc -o CientDT rdict_client.c rdict_clnt.c rdict_xdr.c -lnsl
Now we are ready for testing
References.
1.Douglas E. Comer,David L. Stevens Internet Working with TCP/IP ,vol 3 Client-Server Programming and application Linux/Posix Socket Version, Prentice Hall,Inc. 2001
_________________________________________________________________
Is your PC infected? Get a FREE online computer virus scan from McAfee® Security. http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963
-- redhat-list mailing list unsubscribe mailto:redhat-list-request@xxxxxxxxxx?subject=unsubscribe https://www.redhat.com/mailman/listinfo/redhat-list