0

嗨,我在 C 中的客户端服务器程序遇到了这个问题。这应该是一个非常简单的预订系统......请有人可以帮助我,我不知道如何解决(C 中的第一个项目)。提前致谢

客户端.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>


#define ERRORE -1
#define FLAG 0
#define SIZE 128
#define R 3
#define C 5

typedef struct {
int response_channel;
int service_code;
} request;


typedef struct {
long mtype;
request req;
} request_msg;


typedef struct {
long mtype;
int posti[R][C];
} response_msg;

/*strutture per cancella*/
typedef struct {
int response_channel;
int service_code;
char codice[5];
} request_canc;


typedef struct {
long mtype;
request_canc req;
} request_msg_canc;

typedef struct {
long mtype;
char risp[256];
} response_msg_canc;
//************************************************//

/* strutture per prenota*/
typedef struct {
int response_channel;
int service_code;
int posti[R][C];
} request_pren;

typedef struct {
long mtype;
request_pren req;
} request_msg_pren;

//**********************//



int my_id_coda,id_coda, ret, STATUS;
long key;
int sala[R][C];

request_msg request_message;
response_msg response_message;

/*variabili per cancella*/
request_msg_canc request_message_canc;

request_msg_pren posti_p;

void visualizza();
void prenota();
void cancella();
int menu();

main(int argc, char *argv[]) {
int scelta,ris;

key = getpid();

my_id_coda = msgget(key, IPC_CREAT|IPC_EXCL|0666);
if( my_id_coda == -1){
my_id_coda = msgget(key, IPC_CREAT|0666);
ret = msgctl(my_id_coda,IPC_RMID,0);
my_id_coda = msgget(key, IPC_CREAT|IPC_EXCL|0666);
if( my_id_coda == -1 ){
printf("cannot install client queue, please check with the problem\n");
exit(-1);
}
}


id_coda = msgget(50, IPC_CREAT|0666);
if( id_coda == -1 ){
printf("cannot open server queue, please check with the problem\n");
exit(-1);
}

/*qui mancava il richiamo al menu*/

do{

int a;
printf("1 visualizza;\n");
printf("2 prenota;\n");
printf("3 cancella;\n");
printf("4 esci;\n");
scanf("%d",&a);

scelta = a;

switch(scelta) {
case 1: visualizza(); break;
case 2: prenota(); break;
case 3: cancella(); break;
}
}while(scelta != 4); 
ris=msgctl(my_id_coda,IPC_RMID,0);
if(ris==-1)printf("Errore nella chiamata msgctl");
exit(-1);

}/* end main*/


void visualizza() {
int i,j;
request_message.mtype = 1;
request_message.req.service_code = 1;
request_message.req.response_channel = my_id_coda;
printf("response channel has id %d\n",my_id_coda);

if ( msgsnd(id_coda, &request_message, sizeof(request), FLAG) == -1 ) {
printf("cannot send request to the server\n");
exit(-1);
}


if ( msgrcv(my_id_coda, &response_message, sizeof(response_msg), 1, FLAG) == -1) { 
printf("error while receiving the server response, please check with the problem\n");
exit(-1);
}
else {

memcpy((char*)sala,(char*)response_message.posti,128);
printf("\nla sala è:\n");
for(i=0;i<R;i++){
for(j=0;j<C;j++){
printf("%d ",sala[i][j]);
}
printf("\n");
}

}
}

void prenota(){

int i,j;
int numero=0;
int fila=0;
int poltrona=0;
response_msg_canc risposta_codice;

for(i=0;i<R;i++)
for(j=0;j<C;j++)
posti_p.req.posti[i][j]=0;
numero=0;
while(numero>R*C || numero<=0){
printf("Digitare il numero di posti che si vuole prenotare compreso tra 1 e %d\n",R*C);
scanf("%d",&numero);
}
for(i=0;i<numero;i++){
printf("Digitare il %d° posto nel formato 'fila poltrona' con fila compresa tra 1..%d e poltrona tra 1..%d \n",i+1,R,C);
scanf("%d%d",&fila,&poltrona);
/*scanf("%d",&fila);
scanf("%d",&poltrona);*/
if(fila<=0 || fila>R || poltrona<=0 || poltrona>C){
printf("ERRORE\n");
i--;
}
else {posti_p.req.posti[fila-1][poltrona-1]=1;}
}

for(i=0;i<R;i++){
for(j=0;j<C;j++){
printf("%d",posti_p.req.posti[i][j]);
}
printf("\n");
}
posti_p.mtype = 2;
posti_p.req.service_code = 2;

posti_p.req.response_channel = my_id_coda;

if ( msgsnd(id_coda, &posti_p, sizeof(request_pren), FLAG) == -1 ) {
printf("cannot send request to the server\n");
exit(-1);
}

if ( msgrcv(my_id_coda, &risposta_codice, sizeof(response_msg_canc), 2, FLAG) == -1) { 
printf("error while receiving the server response, please check with the problem\n");
exit(-1);
}
printf("%s\n",risposta_codice.risp);

} 


/* metodo cancella*/

void cancella(){ 
int i,j;
char preno[5];
response_msg_canc risposta;

request_message_canc.mtype = 3;
request_message_canc.req.service_code = 3;

printf("Inserire codice prenotazione da cancellare:");
scanf("%s",preno);
strcpy(request_message_canc.req.codice,preno);


request_message_canc.req.response_channel = my_id_coda;
printf("response channel has id %d\n",my_id_coda);

if ( msgsnd(id_coda, &request_message_canc, sizeof(request_canc), FLAG) == -1 ) {
printf("cannot send request to the server\n");
exit(-1);
}

if ( msgrcv(my_id_coda, &risposta,sizeof(response_msg_canc), 3, FLAG) == -1) { 
printf("error while receiving the server response, please check with the problem\n");
exit(-1);
}
risposta.risp[255]='\0';
printf("%s\n",risposta.risp);
}

服务器.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <math.h>
#include<stdlib.h>
#include<string.h>
#include <sys/sem.h>

#define ERRORE -1
#define FLAG    0
#define SIZE  128
#define R 3
#define C 5
#define CINEMA "prenotazione"
#define STDOUT 1

typedef struct {
    int response_channel;
    int service_code;
} request;

typedef struct {
    int response_channel;
    int service_code;
    char codice[5];
} request_canc;

typedef struct {
    long mtype;
    request_canc req;
} request_msg_canc;

typedef struct {
    long mtype;
    request req;
} request_msg;


typedef struct {
    long mtype;
    int posti[R][C];
} response_msg;

typedef struct {
    char pren[6];
} codice;

typedef struct {
    long mtype;
    char risp[256];
} response_msg_canc;

/* strutture per prenota*/
typedef struct {
    int response_channel;
    int service_code;
    int posti[R][C];
} request_pren;

typedef struct {
    long mtype;
    request_pren req;
} request_msg_pren;


//**********************//


codice prenotazioni[R][C];
int id_coda, ret;
long key = 50;


request_msg  request_message;
request_msg  *new_message;
pthread_t tid;
response_msg response_message;

request_msg_canc request_mes_canc;
request_msg_canc *new_mes_canc;

request_msg_pren request_mes_pren;
request_msg_pren *new_mes_pren;


int ds_shm;

int id_sem;

void ito(int,char*);
int crea_init_sem(key_t,int);
void elimina_sem(int);
int sem_wait(int);
int sem_signal(int);
void visualizza(request_msg*);
void prenota (request_msg_pren*);
void cancella (request_msg_canc*);


main(int argc, char *argv[]) {
    codice prenot[3][5];

    int sd,size,occ,i,j,status,eli;
    long chiave=10,chiave_sem=50;

    char buff[5],app[5],*p,*scorri_mem;


    sd=open(CINEMA,O_RDONLY);


    ds_shm = shmget(chiave,sizeof(codice[3][5]),IPC_CREAT|0666);
    if( ds_shm == -1) {printf("Errore nella chiamata shmget\n"); exit(1);}

    p = shmat(ds_shm, 0, SHM_W);
    if(p==(char*)-1){printf("Errore nella chiamata shmat\n"); exit(1);}
    scorri_mem=p;
    for(i=0;i<R;i++){
       for(j=0;j<C;j++){
       size=read(sd,buff,5);
       memcpy((char*)app,(char*)buff,size);
       strncpy(scorri_mem,app,5);
       *(scorri_mem+5)='\0';
       printf("%s",scorri_mem);
       scorri_mem+=6;
       }
    }
    id_sem=crea_init_sem(chiave_sem,1);


    id_coda = msgget(key, IPC_CREAT|IPC_EXCL|0666);
    if( id_coda == -1){
    id_coda = msgget(key, IPC_CREAT|0666);
    ret = msgctl(id_coda,IPC_RMID,0);
    id_coda = msgget(key, IPC_CREAT|IPC_EXCL|0666);
    if( id_coda == -1 ){
        printf("cannot install server queue, please check with the problem\n");
        exit(-1);
    }
    }

    //close(sd);
    if(fork()==0){ 


    while(1) {

    if ( msgrcv(id_coda, &request_message, sizeof(request), 1, FLAG) == -1) { 
        printf("message receive error, please check with the problem\n");
    }
    else {


            new_message = malloc(sizeof(request_msg));
        if(!new_message){
            printf("cannot allocate new request message buffer \n");
            exit(-1);
        }
        memcpy((char*)new_message,(char*)&request_message,sizeof(request_msg));  



        if( pthread_create(&tid, NULL, visualizza, (void *)new_message) != 0){
            printf("cannot create new thread \n");
            exit(-1);
        }



    }
    }/* end while */
  }/* end fork*/

  // prenota
  if(fork()==0){while(1) {

    if ( msgrcv(id_coda, &request_mes_pren, sizeof(request_pren), 2, FLAG) == -1) { 
        printf("message receive error, please check with the problem\n");
    }
    else {

            new_mes_pren = malloc(sizeof(request_msg_pren));
        if(!new_mes_pren){
            printf("cannot allocate new request message buffer \n");
            exit(-1);
        }
        memcpy((char*)new_mes_pren,(char*)&request_mes_pren,sizeof(request_pren));   

        if( pthread_create(&tid, NULL, prenota, (void *)new_mes_pren ) != 0){
            printf("cannot create new thread \n");
            exit(-1);
        }



    }
    }/* end while */
  }/* end fork*/


  // cancella
    if(fork()==0){ while(1) {

    if ( msgrcv(id_coda, &request_mes_canc, sizeof(request_canc), 3, FLAG) == -1) { 
        printf("message receive error, please check with the problem\n");
    }
    else {

            new_mes_canc = malloc(sizeof(request_msg_canc));
        if(!new_mes_canc){
            printf("cannot allocate new request message buffer \n");
            exit(-1);
        }
        memcpy((char*)new_mes_canc,(char*)&request_mes_canc,sizeof(request_canc));   

        if( pthread_create(&tid, NULL, cancella, (void *)new_mes_canc ) != 0){
            printf("cannot create new thread \n");
            exit(-1);
        }



    }
    }/* end while */
  }/* end fork*/
    wait(&status);
    eli=msgctl(ds_shm,IPC_RMID,NULL);
    if(eli == -1) printf("Errore nella chiamata msgctl");
    elimina_sem(id_sem);
}

void visualizza(request_msg *request_message){

    int status,i,j,occ;
    char *p;

    printf("asked service of type %d - response channel is %d\n", request_message->req.service_code,request_message->req.response_channel); 

    response_message.mtype = 1;

    p = shmat(ds_shm, 0, SHM_R);
    if(p==(char*)-1){printf("Errore nella chiamata shmat\n"); exit(1);}

    for(i=0;i<R;i++){
       for(j=0;j<C;j++){
       strncpy(prenotazioni[i][j].pren,p,6);
       p+=6;
       }
    }

    for(i=0;i<R;i++)
       for(j=0;j<C;j++){
       occ=strncmp(prenotazioni[i][j].pren,"0000",4);
       if(occ==0) response_message.posti[i][j]=0;
       else response_message.posti[i][j]=1;
      }

    if ( msgsnd(request_message->req.response_channel, &response_message, sizeof(response_msg), FLAG) == -1 ) {
    printf("cannot return response to the client\n");
    exit(-1);
    }
    i=shmdt(p);
    free(request_message);
    status = 0;
    pthread_exit((void *)&status);

}

void prenota (request_msg_pren *request_mes_pren){

    response_msg_canc risposta_pren;
    int status,occ,i,j,dist,trovato,cod,sd,doppio,conta=0;
    char *p,c[6],*scorri_mem;

    risposta_pren.mtype = 2;

    sem_wait(id_sem);

     p = shmat(ds_shm, 0, SHM_R);

    if(p==(char*)-1){printf("Errore nella chiamata shmat\n"); exit(1);}
    scorri_mem=p;
    for(i=0;i<R;i++){
       for(j=0;j<C;j++){
       strncpy(prenotazioni[i][j].pren,scorri_mem,6);
       scorri_mem+=6;
       }
    }
    scorri_mem=p;

    for(i=0;i<R;i++)
       for(j=0;j<C;j++){
       occ=strncmp(prenotazioni[i][j].pren,"0000",4);
       if(occ==0) response_message.posti[i][j]=0;
       else response_message.posti[i][j]=1;
      }


    for(i=0;i<R;i++)
       for(j=0;j<C;j++){
         if(request_mes_pren->req.posti[i][j]==1)
           if(request_mes_pren->req.posti[i][j]==response_message.posti[i][j])
               trovato=1;
          if(request_mes_pren->req.posti[i][j]==0) conta++;  
       }
     i=shmdt(p);
     p = shmat(ds_shm, 0, SHM_R);
     scorri_mem=p;
    if(trovato==1 || conta==(R*C)){  strcpy(risposta_pren.risp,"prenotazione non effettuata");} 
    else {
          do{
          cod=random();
          ito(cod,c);
      doppio=0; 
       for(i=0;i<R;i++){
           for(j=0;j<C;j++){
           occ=strncmp(prenotazioni[i][j].pren,c,4);
           if(occ==0) {doppio=1;break;}
           }
       }
      }while(doppio==1); 
       strcpy(risposta_pren.risp,"prenotazione effettuata con codice: ");
       strncat(risposta_pren.risp,c,6);

       i=shmdt(p);
       p = shmat(ds_shm, 0, SHM_W);
       scorri_mem=p;
       for(i=0;i<R;i++){
            for(j=0;j<C;j++){
        if(request_mes_pren->req.posti[i][j]==1){

           strncpy(scorri_mem,c,6);
                  if(j<(C-1)) *(scorri_mem+4)=' ';
              else (*(scorri_mem+4)='\n');
            }
          *(scorri_mem+5)='\0';
          scorri_mem+=6;
              }
            }
     }
     close(STDOUT);
     scorri_mem=p;
     sd=open(CINEMA,O_RDWR|O_TRUNC);
     dup(sd);
      for(i=0;i<R;i++){
       for(j=0;j<C;j++){
       write (sd,scorri_mem,5);
       scorri_mem+=6;
       }
         }
     //fflush(STDOUT);

    if ( msgsnd(request_mes_pren->req.response_channel, &risposta_pren, sizeof(response_msg_canc), FLAG) == -1 ) {
    printf("cannot return response to the client\n");
    exit(-1);
    }
    close(sd);
    sem_signal(id_sem);
    free(request_mes_pren);
    status = 0;
    pthread_exit((void *)&status);

}


void cancella (request_msg_canc *request_mes_canc){

    response_msg_canc risposta;
    int status,occ,i,j,dist,sd,trovato=0;
    char *p,*scorri_mem;

    risposta.mtype = 3;

    p = shmat(ds_shm, 0, SHM_W);
    if(p==(char*)-1){printf("Errore nella chiamata shmat\n"); exit(1);}
    scorri_mem=p;
    for(i=0;i<R;i++)
       for(j=0;j<C;j++){
       occ=strncmp(scorri_mem,request_mes_canc->req.codice,4);
       if(occ==0) {
                trovato++;
                    if(j<C-1){ strcpy(scorri_mem,"0000 \0");}
                else     { strcpy(scorri_mem,"0000\n");}
              }
       scorri_mem+=6;
    }
     i=shmdt(p);

    sd=open(CINEMA,O_RDWR|O_TRUNC); 
    p = shmat(ds_shm, 0, SHM_R);
    scorri_mem=p;

    for(i=0;i<R;i++){
       for(j=0;j<C;j++){
        write(sd,scorri_mem,5);
        scorri_mem+=6;
       }
    }

        if(trovato>0)  strcpy(risposta.risp,"cancellazione effettuata");
    else       {   strcpy(risposta.risp,"codice inesistente");}

    if ( msgsnd(request_mes_canc->req.response_channel, &risposta, sizeof(response_msg_canc), FLAG) == -1 ) {
    printf("cannot return response to the client\n");
    exit(-1);
    }

    close(sd);
    i=shmdt(p);
    free(request_mes_canc);
    status = 0;
    pthread_exit((void *)&status);

}


void ito(int casuale,char c[]){

    div_t divisione;
    int i,k,j,num=1;


    if(casuale > 999999999) k=9;
    else k=8;

    for(j=0;j<k;j++)
       num=num*10;

    for(i=0;i<4;i++){
       divisione= div(casuale,num);
       switch(divisione.quot) {
       case 0: c[i]='0'; break;
       case 1: c[i]='1'; break;
       case 2: c[i]='2'; break;
       case 3: c[i]='3'; break;
       case 4: c[i]='4'; break;
       case 5: c[i]='5'; break;
       case 6: c[i]='6'; break;
       case 7: c[i]='7'; break;
       case 8: c[i]='8'; break;
       case 9: c[i]='9'; break;
      }
      casuale=divisione.rem;
      num=num/10;;
    }
    c[4]=' ';
    c[5]='\0';
    return ;
}
int crea_init_sem(key_t chiave, int val)
{ 
  int sem;
  sem=semget(chiave,1,IPC_CREAT|0666);
  if (sem==-1)
     { 
       printf("Impossibile creare il semaforo\n");
       exit(1);
     }
  semctl(sem,0,SETVAL,val);
  return(sem);
}

void elimina_sem(int id_sem)
{
  if(semctl(id_sem,IPC_RMID,0)==-1)
    { 
      printf("Impossibile eliminare il semaforo\n");
      exit(1);
    }
}

int sem_wait(int sem)
{
  struct sembuf operazione[1]={{0,-1,0}};
  return semop(sem,operazione,1);
}

int sem_signal(int sem)
{
  struct sembuf operazione[1]={{0,+1,0}};
  return semop(sem,operazione,1);
}

这就是崩溃:

*** stack smashing detected ***: ./Client
======= Memory map: ========

    uca@luca-8:~/Scrivania/tesina/ufficial$ ./Client

    1 visualizza;

    2 prenota;

    3 cancella;

    4 esci;

    2

    Digitare il numero di posti che si vuole prenotare compreso tra 1 e 15

    2

    Digitare il 1° posto nel formato 'fila poltrona' con fila compresa tra 1..3 e poltrona tra 1..5 

    3 1

    Digitare il 2° posto nel formato 'fila poltrona' con fila compresa tra 1..3 e poltrona tra 1..5 

    3 2

    00000

    00000

    11000

    prenotazione effettuata con codice: 1804 

    *** stack smashing detected ***: ./Client terminated

    ======= Backtrace: =========

    /lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0x9408d5]

    /lib/i386-linux-gnu/libc.so.6(+0xe7887)[0x940887]

    ./Client[0x8048c8d]

    ./Client[0x80487aa]

    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x872113]

    ./Client[0x80485c1]

    ======= Memory map: ========

    0019d000-0019e000 r-xp 00000000 00:00 0          [vdso]

    00525000-00541000 r-xp 00000000 08:01 2360250    /lib/i386-linux-gnu/libgcc_s.so.1

    00541000-00542000 r--p 0001b000 08:01 2360250    /lib/i386-linux-gnu/libgcc_s.so.1

    00542000-00543000 rw-p 0001c000 08:01 2360250    /lib/i386-linux-gnu/libgcc_s.so.1

    00859000-009cf000 r-xp 00000000 08:01 2360229    /lib/i386-linux-gnu/libc-2.13.so

    009cf000-009d1000 r--p 00176000 08:01 2360229    /lib/i386-linux-gnu/libc-2.13.so

    009d1000-009d2000 rw-p 00178000 08:01 2360229    /lib/i386-linux-gnu/libc-2.13.so

    009d2000-009d5000 rw-p 00000000 00:00 0 

    00b18000-00b36000 r-xp 00000000 08:01 2360216    /lib/i386-linux-gnu/ld-2.13.so

    00b36000-00b37000 r--p 0001d000 08:01 2360216    /lib/i386-linux-gnu/ld-2.13.so

    00b37000-00b38000 rw-p 0001e000 08:01 2360216    /lib/i386-linux-gnu/ld-2.13.so

    08048000-0804a000 r-xp 00000000 08:01 5636693    /home/luca/Scrivania/tesina/ufficial/Client

    0804a000-0804b000 r--p 00001000 08:01 5636693    /home/luca/Scrivania/tesina/ufficial/Client

    0804b000-0804c000 rw-p 00002000 08:01 5636693    /home/luca/Scrivania/tesina/ufficial/Client

    0809c000-080bd000 rw-p 00000000 00:00 0          [heap]

    b78b1000-b78b2000 rw-p 00000000 00:00 0 

    b78bf000-b78c3000 rw-p 00000000 00:00 0 

    bf8d0000-bf8f1000 rw-p 00000000 00:00 0          [stack]

    Annullato

    luca@luca-8:~/Scrivania/tesina/ufficial$ 
4

2 回答 2

1

这很可能是由这条线引起的:scanf("%s",preno);. 用户可以输入超过 4 个非空格字符并溢出preno[5]缓冲区。考虑对要读取的字符数添加限制(例如"%4s")。

我还看到很多strcpy- 如果缓冲区的容量小于源字符串,则有可能导致缓冲区溢出和粉碎堆栈。考虑将它们全部更改为strncpy,即使您正确分配空间。

于 2012-07-03T11:33:03.730 回答
0

您是否尝试过使用内存分析工具,例如 valgrind

我发现它对于这类问题非常宝贵

它可以提醒您缓冲导致“堆栈粉碎”类型错误的溢出,从而使您能够查明问题

以我的经验,对于任何严肃的 C 开发,我会说值得花时间和精力来学习如何使用这个或等效工具

于 2012-07-03T12:09:45.123 回答