The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Многопотоковые сервера в среде Linux. Техника разработки (rpc linux gcc )


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: rpc, linux, gcc,  (найти похожие документы)
From: Б. А. Державец <dba477 at list.ru> Newsgroups: email Date: Mon, 26 May 2004 14:31:37 +0000 (UTC) Subject: Многопотоковые сервера в среде Linux. Техника разработки Приведенный ниже код является ответом на вопрос 23.10 из [1] стр.350 Однако, файлы dict_cif.c ( rdict_cif.c в [1] ) , содержащий пользовательский код процедуры заглушки клиента, и dict.c (rdict.c в [1]), содержащий блок main( ) клиента , исключены из рассмотрения. Необходимо только модифицировать в соответствии с требованиями задачи код dict_client.c , оригинал которого порождается rpcgen c опциями -a -M . Изначально из [1] взяты только два файла dict.x (rdict.x в [1] стр.329) и dict_srp (rdict_srp в [1] стр. 344 ) ---------------------------------------------------------------------- Multithreaded RPC Servers in Linux environment. Thread safe code writing is a must 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. Note that all business logic is implemented into rdict_client.c file, generated by "rpcgen a M rdict.x" command. So,files rdict.c and rdict_cif (see [1] , Chapter "RPC") are just taken out.See for code details: http://www.opennet.dev/base/dev/rpc_example.txt.html 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 --------------------------------------------------------------------------
Файл dict.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;
Файл dict_srp.c : #include<rpc/rpc.h> #include<string.h> #include "dict.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); } Вызовем rpcgen для генерации кода заглушек xdr-файла и файла dict.h : $rpcgen -a -M dict.x
Модифицированные файлы на стороне сервера (ср. rdict_sif.c из [1] стр.340 ): /* * dict_sif.c */ #include<rpc/rpc.h> #define RPC_SVC #include "dict.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); }
Модифицированная заглушка сервера файл dict_svc.c . Многопотоковая версия: /* Modified dict_svc.c ( multithreaded version) * * Please do not edit this file. * It was generated using rpcgen. */ #include "dict.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; /* Процедура выполняемая потоком */ 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; } /* Принципиально измененный код процедуры rdictprog_1 , стартующей поток для каждого клиентского запроса на запуск удаленной процедуры */ 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 */ }
Сборка сервера: $ gcc -o ServerDT dict_svc.c dict_sif.c dict_srp.c dict_xdr.c -lpthread -lnsl Модифицированный файл dict_client.c (ср. rdict.c [1] стр. 341). Образец создан командой: $rpcgen -a -M dict.x /* dict_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 "dict.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); }
Сборка клиента: $ gcc -o CientDT dict_client.c dict_clnt.c dict_xdr.c -lnsl Теперь все готово для тестирования. Литература 1.Дуглас Э. Крамер,Дэвид Л. Стивенс. Сети TCP/IP .Разработка приложений типа клиент/сервер для LINUX/POSIX . Том 3 .Издательский дом "Вильямс",2002. 2. http://www.opennet.dev/base/dev/pthread_select_server.txt.html

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

Обсуждение [ RSS ]
  • 1, Vasya (??), 11:36, 11/02/2005 [ответить]  
  • +/
    У меня на Red Hat 9 это не заработало.
     
     
  • 2, Vasya (??), 17:25, 11/02/2005 [^] [^^] [^^^] [ответить]  
  • +/
    glibc версии 2.3.3
     

  • 3, Mage (??), 13:44, 01/11/2006 [ответить]  
  • +/
    Вся проблема в том, что после запуска функцией rdictprog_1 потока serv_request осуществляется завершение ее (rdictprog_1) работы, а следовательно все соединения с клиентом закрываются, отсюда следует, что поток уже пытается обработать закрытое соединение и умирает при первом же обращении к функции rpc_getargs. Интересно, у кого-нибудь заработал этот пример?
    glibc версии 2.4-4
     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру