LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Distributions > Red Hat
User Name
Password
Red Hat This forum is for the discussion of Red Hat Linux.

Notices


Reply
  Search this Thread
Old 06-02-2004, 08:54 AM   #1
dba477
LQ Newbie
 
Registered: Jun 2004
Posts: 1

Rep: Reputation: 0
Multithreaded RPC Servers for Linux.Thread-safe code writing


This article is supposed to give a positive answer for the question 23.10 from [1] Chapter "RPC"
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 "rpcgen -a -M rdict.x"
command. Files rdict.c and rdict_cif.c (see [1] , Chapter "RPC") are taken out to
highlight the core of RPC technology.

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:


/*
* 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
 
Old 08-25-2010, 12:33 AM   #2
sundararaja88
LQ Newbie
 
Registered: Aug 2010
Posts: 2

Rep: Reputation: 0
Smile rpc two side connection

hai,
this code connect only client to server but i want server also access the client side procedure in reverse way but i will try.but it didn't work.i have included server and client module in both side but server dosen't access the client procedure through rpc.anyway to create two way connection established through rpc connection.plz help me.i will need this module for my project.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
NFS RPC: Port mapper failure - RPC: Unable to receive KEJP Linux - Networking 6 12-18-2006 02:14 AM
Writing UDP servers with Xinetd kidskc Programming 1 11-15-2005 05:41 PM
What is thread safe....??? rajsun Programming 5 04-26-2005 11:33 PM
Book about writing secure code Covel Linux - Security 1 06-12-2004 01:53 AM
Multithreaded System On 4 Cpu Linux Machine, process stuck on certain thread eyalzm Programming 1 05-10-2004 11:46 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Distributions > Red Hat

All times are GMT -5. The time now is 09:15 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration