DPD ha scritto:
Nell'esempio le parole lette in input sono già terminate con INVIO.
Tutto molto chiaro.
Sulla base dei tuoi suggerimenti ho scritto un programma server per una esercitazione di cui allego il codice. Certamente si può fare molto meglio, ma considera che sto imparando.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <malloc.h>
#define MAXCONN 5
#define BENVENUTO "Benvenuto nel server conta occorrenze \r\n"
#define RICHIESTA "Invia la parola\r\n"
struct Tag_Nodo {
char *Parola;
int Ripetizioni;
struct Tag_Nodo *Next;
};
typedef struct Tag_Nodo Tipo_Nodo;
typedef Tipo_Nodo *Tipo_Lista;
// Prototipi
void addressInit(struct sockaddr_in *indirizzo, int port, long IPaddr);
void parolaRicevuta(int sockDesc,char *s);
Tipo_Lista Insert(Tipo_Lista l, char *parola, int ripetizioni);
Tipo_Nodo *Search(Tipo_Lista l, char *parola);
void Is_Empty(Tipo_Lista l);
Tipo_Lista Inizializza(Tipo_Lista l);
int main (unsigned argc, char **argv) {
int SERVER_PORT, sock, client_len, fd;
struct sockaddr_in server, client;
char risposta[40];
Tipo_Lista listaParole = NULL;
Tipo_Nodo *NodoTrovato;
int ripetizioni;
//char parola;
char *parola;
listaParole = Inizializza(listaParole);
if (argc != 2) {
fprintf(stderr, "Sintassi: %s <porta>\n", argv[0]);
exit(4);
}
SERVER_PORT = atoi(argv[1]);
/* impostazione del transport end point */
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("chiamata alla system call socket fallita");
exit(1);
}
/* inizializzo la struttura dell'indirizzo internet del server
la funzione utilizzata copia 0 nei primi strlen(myServer) byte dell'oggetto puntato
da &server, operando in pratica un azzeramento della struttura. */
memset ( &server, 0, sizeof(server) );
addressInit(&server, SERVER_PORT, INADDR_ANY);
/* binding dell'indirizzo al transport end point */
if (bind(sock, (struct sockaddr *)&server, sizeof server) == -1) {
perror("chiamata alla system call bind fallita");
exit(2);
}
/* imposto il server in modo che possa gestire 5 richieste
contemporaneamente */
listen(sock, MAXCONN);
/* inserisco questa chiamata per evitare che il figlio resti 'zombie'
dovendo restituire il codice di ritorno al padre */
signal(SIGCHLD,SIG_IGN);
/* gestione delle connessioni dei client */
while (1) {
client_len = sizeof(client);
if ((fd = accept(sock, (struct sockaddr *)&client, &client_len)) < 0) {
perror("Errore di accept della connessione");
exit(3);
}
/* ogni volta che il server accetta una nuova connessione,
quest'ultima viene gestita da un nuovo processo figlio */
switch(fork()) {
case -1:
perror("Errore nella chiamata alla fork");
exit(4);
case 0:
fprintf(stderr, "Aperta connessione (PID %d).\n",getpid());
send(fd, BENVENUTO, strlen(BENVENUTO), 0);
send(fd, RICHIESTA, strlen(RICHIESTA), 0);
parolaRicevuta(fd,parola);
/* Se la parola non esiste la inserisce nella lista con
ripetizione = 0
Se la parola esiste incrementa di 1 il contatore */
NodoTrovato = Search(listaParole, parola);
// ripetizioni = NodoTrovato;
if (NodoTrovato != NULL){
ripetizioni = 0;
listaParole = Insert(listaParole, parola, ripetizioni);
}
else {
ripetizioni = listaParole->Ripetizioni;
}
sprintf(risposta,"Il numero di occorrenze e' %d\n",ripetizioni);
send(fd,risposta,strlen(risposta),0);
close(fd);
fprintf(stderr, "Chiusa connessione (PID %d).\n",getpid());
}
}
}
/**************************************************************************************************************************/
void addressInit(struct sockaddr_in *indirizzo, int port, long IPaddr)
{
// Creo l'indirizzo Internet locale
indirizzo->sin_family = AF_INET;
indirizzo->sin_port = htons((u_short) port); // ordinamento dei Byte da Host a Rete
/* indicando INADDR_ANY viene collegato il socket all'indirizzo locale IP
* dell'interaccia di rete che verrà utilizzata per inoltrare il datagram IP */
indirizzo->sin_addr.s_addr = IPaddr;
}
void parolaRicevuta(int sockDesc,char *s){
int i=0;
int charRecv = 0;
char c;
charRecv = recv(sockDesc, &c, 1, 0);
while (c !='\n'){
s[i++]=c;
charRecv = recv(sockDesc, &c, 1, 0);
} // End while (c !='\n')
s[i]='\0';
}
Tipo_Lista Inizializza(Tipo_Lista l)
{
return (l = NULL);
}
Tipo_Lista Insert(Tipo_Lista l, char *parola, int ripetizioni)
{
Tipo_Lista Prec = NULL;
Tipo_Lista Succ = l;
Tipo_Lista Temp;
while ( (Succ != NULL) && (strcmp(parola,Succ->Parola) > 0) )
{
Prec = Succ;
Succ = Succ->Next;
}
Temp = (Tipo_Lista) malloc(sizeof(Tipo_Nodo));
if (Temp == NULL)
{
printf("\nErrore nell'allocazione.\n");
exit(1);
}
if (Prec == NULL)
{
Temp->Parola = parola;
Temp->Ripetizioni = 0;
Temp->Next = Succ;
return Temp;
}
else
{
Temp->Parola = parola;
Temp->Ripetizioni = ripetizioni;
Temp->Next = Succ;
Prec->Next = Temp;
return l;
}
}
Tipo_Nodo *Search(Tipo_Lista l, char *parola)
{
while ( (l != NULL) && (strcmp(parola,l->Parola) > 0) )
l = l->Next;
if ( (l != NULL) && (strcmp(l->Parola,parola) == 0) ){
l->Ripetizioni++;
return l;}
else
return NULL;
}
Si tratta di un Server in attesa su una porta di più connessioni client (max 5). Quando arriva una richiesta di connessione, permette l'invio di una parola da parte del client e dovrebbe rispondere con il numero di occorrenze di quella parola se già vi è stata una trasmissione della stessa.
Compilato con Cygwin, non mi dà errori.
Il problema è nel momento in cui lo lancio. Funziona tutto fino alla procedura
parolaRicevuta. Al primo carattere trasmesso dal client ho questo messaggio in Cygwin:
5 [main] myserver 2736 _cygtls:: handle_exception: Error while dumping state (probably corrupted stack). Ovviamente 2736 è il PID.
Ci sto ammattendo, ma non riesco a trovare l'inghippo. Cosa ne pensi ?
Ciao e grazie ancora.