Gli esempi mostrati di seguito sono tratti dal libro UNIX: PROGRAMMAZIONE AVANZATA disponibile presso la biblioteca dell'istituto.
Per gli approfondimenti ed i commenti si rimanda a tale testo.
La libreria che segue viene utilizzata dal client. Prepara il messaggio da inviare al server, e si mette in attesa della risposta.
/*********************************/ /* dblib.c */ /*********************************/ #include#include #include #include "dbms.h" extern int errno; static MESSAGE m; static STATUS dbmscall(r) RCD *r; { char *dbmsval, *getenv(); static long dbmskey; long atol(); if (dbmskey == 0) { if((dbmsval = getenv("DBMSKEY")) == NULL) fatal("manca la variabile di environment DMSKEY"); dbmskey=atol(dbmsval); } if (m.clientkey == 0) m.clientkey=getpid(); if(!send(dbmskey,&m,sizeof(m))) return(ERROR); if(!receive(m.clientkey,&m,sizeof(m))) return(ERROR); if(r!= NULL) *r=m.rcd; if(m.status == ERROR) errno=m.errno; else errno=0; return(m.status); } STATUS Dopen(file) char *file; { m.cmd = 'o'; strcpy(m.file,file); return(dbmscall(NULL)); } STATUS Dcreate(file) char *file; { m.cmd='c'; strcpy(m.file,file); return(dbmscall(NULL)); } STATUS Dclose() { STATUS status; m.cmd='q'; status=dbmscall(NULL); rmqueue(m.clientkey); return(status); } STATUS Dtop() { m.cmd='t'; return(dbmscall(NULL)); } STATUS Dget(name,r) char *name; RCD *r; { m.cmd='g'; strcpy(m.rcd.name,name); return(dbmscall(r)); }
La seguente librerie viene utilizzata dal server. In base all'analisi del comando giunto dal client viene eseguita l'operazione corretta e viene inviato l'esito dell'operazione al client.
/********************************/ /* dbms.c */ /********************************/ #include#include #include "dbms.h" static int fd=-1; static STATUS Dopen(file) char *file; { if ((fd=open(file,O_RDWR,0))==-1) return(ERROR); return(OK); } static STATUS Dcreate(file) char *file; { if ((fd=open(file,O_RDWR | O_CREAT | O_TRUNC,0666))==-1) return(ERROR); return(OK); } static STATUS Dclose() { if(close(fd)==-1) return(ERROR); return(OK); } long lseek(); extern int errno; static STATUS Dtop() { if (lseek(fd,0L,0)==-1) return(ERROR); return(OK); } static STATUS Dget(name,r) char *name; RCD *r; { int nread; if(Dtop()!=OK) return(ERROR); while((nread=read(fd,r,sizeof(RCD)))==sizeof(RCD)) if (strcmp(r->name,name)==0){ if(lseek(fd,-(long)sizeof(RCD),1)==-1) return(ERROR); return(OK); } switch(nread){ case 0: return(NOTFOUND); case -1: return(ERROR); default: errno=0; return(ERROR); } } static STATUS Dgetnext(r) RCD *r; { while(1) switch(read(fd,r,sizeof(RCD))) { case sizeof(RCD): if (r->name[0]=='\0') continue; return(OK); case 0: return(NOTFOUND); case -1: return(ERROR); default: errno=0; return(ERROR); } } static STATUS Dput(r) RCD *r; { RCD rcd; switch(Dget(r->name,&rcd)) { case NOTFOUND: if (lseek(fd,0l,2)==-1) return(ERROR); break; case ERROR: return(ERROR); } switch (write(fd,r,sizeof(RCD))) { case sizeof(RCD): return(OK); case -1: return(ERROR); default: errno=0; return(ERROR); } } static STATUS Ddelete(name) char *name; { RCD rcd; switch(Dget(name,&rcd)) { case NOTFOUND: return(OK); case ERROR: return(ERROR); } rcd.name[0]='\0'; switch (write(fd,&rcd,sizeof(RCD))) { case sizeof(RCD): return(OK); case -1: return(ERROR); default: errno=0; return(ERROR); } } /********************************/ /* demodbms.c */ /********************************/ #include #include #include #include "dbms.h" #include "defs.h" static void rcdprint(r) RCD *r; { printf("Nome\t%s\n",r->name); printf("Indirizzo\t%s\n",r->street); printf("Citta'\t%s\n",r->city); printf("Stato\t%s\n",r->state); printf("Cap\t%s\n",r->zip); printf("Telefono\t%s\n",r->tel); } static void prompt(msg,result,max,required) char *msg, *result; int max; BOOLEAN required; { char s[200]; int len; while(1) { printf("\n%s?",msg); if(gets(s) == NULL) exit(0); len=strlen(s); if(len >=max) { printf("Risposta troppo lunga\n"); continue; } if(len == 0 && required) { printf("Valore obbligatorio\n"); continue; } strcpy(result,s); return; } } main() { char cmd[5], file[50], name[30]; RCD rcd; extern int errno; while(1) { prompt("Comando (? per aiuto)",cmd,sizeof(cmd), TRUE); if(strlen(cmd) != 1) { printf("Una sola lettera\n"); continue; } switch(cmd[0]) { case '?': printf("o apre un database\n"); printf("c crea un database\n"); printf("p inserisce un record\n"); printf("d cancella un record\n"); printf("g trova un record per key\n"); printf("n trova il record successivo\n"); printf("t si posiziona all'inizio del database\n"); printf("q termina l'esecuzione\n"); continue; case 'o': prompt("File da aprire",file,sizeof(file),TRUE); if(Dopen(file) == OK) printf("OK\n"); else printf("Non riesco; errno=%d\n",errno); continue; case 'c' : prompt("File da creare",file,sizeof(file), TRUE); if(Dcreate(file) == OK) printf("OK\n"); else printf("Non riesco; errno=%d\n",errno); continue; case 'q' : if (Dclose() == OK) printf("OK\n"); else printf("Non riesco; errno=%d\n",errno); exit(0); case 'g' : prompt("Nome",name,sizeof(name), TRUE); switch(Dget(name,&rcd)) { case OK: rcdprint(&rcd); continue; case NOTFOUND: printf("Non trovato\n"); continue; case ERROR: printf("Non riesco; errno=%d\n",errno); continue; } case 'n': switch(Dgetnext(&rcd)) { case OK: rcdprint(&rcd); continue; case NOTFOUND: printf("Non trovato\n"); continue; case ERROR: printf("Non riesco; errno=%d", errno); continue; } case 'p' : prompt("Nome",rcd.name,sizeof(rcd.name),TRUE); prompt("Indirizzo",rcd.street,sizeof(rcd.street), FALSE); prompt("Citta'",rcd.city,sizeof(rcd.city),FALSE); prompt("Stato",rcd.state,sizeof(rcd.state),FALSE); prompt("Cap",rcd.zip,sizeof(rcd.zip), FALSE); prompt("Telefono",rcd.tel,sizeof(rcd.tel), FALSE); if(Dput(&rcd) == OK) printf("OK\n"); else printf("Non riesco; errno=%d\n",errno); continue; case 'd': prompt("Nome",name,sizeof(rcd.name), TRUE); if(Ddelete(name) == OK) printf("OK\n"); else printf("Non riesco; errno=%d\n",errno); continue; case 't' : if(Dtop() == OK) printf("OK\n"); else printf("Non riesco; errno=%d\n",errno); continue; default: printf("Comando sconosciuto - usare ? per aiuto\n"); } } } #include void fatal(msg) char *msg; { fprintf(stderr, "ERROR: %s\n", msg); exit(1); } /********************************/ /* main.c */ /********************************/ #include #include #include #include "dbms.h" main() { MESSAGE m; char *dbmsval,name[30],*getenv(); long dbmskey,atol(); if ((dbmsval=getenv("DBMSKEY"))==NULL) fatal("manca la variabile di enviorment DBMSKEY"); dbmskey=atol(dbmsval); while(receive(dbmskey,&m,sizeof(m))) { switch(m.cmd) { case 'o': m.status=Dopen(m.file); break; case 'c': m.status=Dcreate(m.file); break; case'q': m.status=Dclose(); rmqueue(dbmskey); break; case 'g': strcpy(name,m.rcd.name); m.status=Dget(name,&m.rcd); break; case 'n': m.status=Dgetnext(&m.rcd); break; case 'p': m.status=Dput(&m.rcd); break; case 'd': m.status=Ddelete(m.rcd.name); break; case 't': m.status=Dtop(); break; default: errno=EINVAL; m.status=ERROR; } m.errno=errno; if (!send(m.clientkey,&m,sizeof(m))) printf("non posso inviare a %ld;errno=%ld\n",m.clientkey,errno); if (m.cmd=='q') exit(0); } syserr("receive"); } #include #include #include #include "defs.h" #define MAXMSG 4096 #define MAXOPEN 20 #define BADADDR (char *) (-1) static BOOLEAN findinfo(key,sndsidp,rcvsidp,addrp,segidp) int key; int *sndsidp,*rcvsidp,*segidp; char **addrp; { static struct { int key; int sndsid; int rcvsid; char *addr; int segid; } sems[MAXOPEN]; int i,avail; extern int errno; char *shmat(); avail=-1; for (i=0;i MAXMSG) nbytes=MAXMSG; P(sndsid); memcpy(addr,buf,nbytes); V(rcvsid); return(TRUE); } BOOLEAN receive(srckey,uf,nbytes) int srckey; char *uf; int nbytes; { int sndsid,rcvsid,segid; char *addr; if (!findinfo(srckey,&sndsid,&rcvsid,&addr,&segid)) return(FALSE); if (nbytes>MAXMSG) nbytes=MAXMSG; P(rcvsid); memcpy(uf,addr,nbytes); V(sndsid); return(TRUE); } void rmqueue(key) int key; { int sndsid,rcvsid,segid; char *addr; if (!findinfo(key,&sndsid,&rcvsid,&addr,&segid)) syserr("findinfo"); (void)semctl(sndsid,0,IPC_RMID,0); (void)semctl(rcvsid,0,IPC_RMID,0); (void)shmdt(addr); (void)shmctl(segid,IPC_RMID,0); } #include #include #include int semtran(key) int key; { int sid; if ((sid=semget((key_t)key, 1,0666 | IPC_CREAT)) == -1) syserr("semget"); return(sid); } static void semcall(sid,op) int sid; int op; { struct sembuf sb; sb.sem_num=0; sb.sem_op=op; sb.sem_flg=0; if (semop(sid,&sb,1) == -1) syserr("semop"); } void P(sid) int sid; { semcall(sid,-1); } void V(sid) int sid; { semcall(sid,1); } #include void syserr(msg) /* stampa un messaggio di errore di una */ /* chiamata di sistema e termina */ char *msg; { extern int errno, sys_nerr; extern char *sys_errlist[]; fprintf(stderr,"ERROR: %s ( %d",msg, errno); if (errno > 0 && errno < sys_nerr) fprintf(stderr,": %s)\n",sys_errlist[errno]); else fprintf(stderr,")\n"); exit(1); } /************************************/ /* dbms.h */ /************************************/ typedef enum {OK, NOTFOUND, ERROR} STATUS; typedef struct { char name[20]; char street[15]; char city[10]; char state[3]; char zip[6]; char tel[15]; }RCD; typedef struct { long mtype; long clientkey; char cmd; char file[20]; RCD rcd; STATUS status; int errno; } MESSAGE; /**********************/ /* defs.h */ /**********************/ typedef enum {TRUE, FALSE} BOOLEAN; #define lowbyte(w) ((w) & 0377) #define highbyte(w) lowbyte((w)>> 8)