Joker91
29-01-2013, 16:45
Rieccomi qui, col solito programma un server-molti client con l'utilizzo di socket... Server e client ovviamente sono processi separati.Il server crea un thread worker per ogni richiesta di un client.
Sono totalmente nel panico perchè non so più dove andare a parare...
Il client invia il messaggio al server correttamente (questo posso assicurarlo, il formato del messaggio è corretto). Il server fa una accept e fa partire un thread worker... Il worker quindi fa una read sulla socket.. Qui la tragedia: il programma rimane bloccato su questa read finchè non lo termino io manualmente.
Non riesco proprio a capire il perchè... Non credo ci sia qualche errore di scrittura ma un problema proprio della struttura, quindi non state troppo a concentrarvi sul codice.. Vi metto un po' di codice e le considerazioni che ho fatto in fondo alla pagina:
SERVER:
int main(int argc, char *argv[]){
int sfd, sfd1, i,err;
pthread_t tid;
/* dichiarazioni + altre elaborazioni non importanti */
}
if ((sfd = createServerChannel(skt_bib))== -1){
fprintf(stderr,"SERVER: errore creazione socket server\n");
exit(EXIT_FAILURE);
}
while (sfd1 = acceptConnection(sfd) != -1) ){
if ((err=pthread_create(&tid,NULL,&worker,(void*)sfd1)) != 0){
fprintf(stderr,"SERVER: errore creazione worker\n");
exit(EXIT_FAILURE);
}
thread++;
}
/* altra roba non pertinente */
return 0;
}
Come vedete utilizza due funzioni: createServerChannel che crea il socket, la acceptConnetion è semplicemente una accept. Comunque ecco il codice:
int createServerChannel(char* path){
int s;
struct sockaddr_un sa;
if (path == NULL) {errno = EINVAL; return -1;}
if (strlen(path) > UNIX_PATH_MAX) {errno = E2BIG; return -1;}
if (fnmatch("./tmp/*.sck",path,FNM_PATHNAME)) {errno = EINVAL; return -1;}
strncpy(sa.sun_path, path, UNIX_PATH_MAX);
sa.sun_family = AF_UNIX;
ec_meno1(s=socket(AF_UNIX,SOCK_STREAM,0));
if (bind(s,(struct sockaddr *)&sa,sizeof(sa)) == -1) {
ec_meno1(closeServerChannel(path,s));
return -1;
}
if (listen(s,SOMAXCONN) == -1) {
ec_meno1(closeServerChannel(path,s));
return -1;
}
return s;
}
int acceptConnection(int s){
int c = accept(s,NULL,0);
return c;
}
Dopo aver accettato la connessione esegue il thread worker che rimane bloccata subito su una receive (la funzione la metto alla fine del post):
void* worker(void* arg){
int sfd = (int) arg;
message_t* msg = malloc(sizeof(message_t));
if (receiveMessage(sfd,msg) == -1){
fprintf(stderr,"SERVER: errore ricezione messaggio");
pthread_exit(0);
}
}
Ora il client:
int main(int argc, char *argv[]){
int i, j, csfd;
int k = 0;
FILE* fd;
int len = 0;
/* roba inutile */
while (!feof(fd)){
fgets(bib_name,100,fd);
j=0;
while ((bib_name[j] != '\n') && (j<strlen(bib_name)))
j++;
if (bib_name[j] == '\n')
bib_name[j] = '\0';
sprintf(addr,"./tmp/%s.sck",bib_name);
if ((csfd=openConnection(addr,NTRIAL,NSEC)) == -1 ){
fprintf(stderr,"CLIENT: errore apertura socket\n");
exit(EXIT_FAILURE);
}printf("CLIENT: %d\n",csfd);
if ((sendMessage(csfd,out)) == -1){
fprintf(stderr,"CLIENT: errore invio messaggio\n");
exit(EXIT_FAILURE);
}
if (receiveMessage(csfd,in) == -1){
fprintf(stderr,"CLIENT: errore ricezione messaggio\n");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
anche qui ho lasciato le robe che presumo importanti per capire l'errore. Il client apre la connessione al socket con la openConnection:
int openConnection(char* path, int ntrial, int k){
int prove, fd;
struct sockaddr_un sa;
if (path == NULL) {errno = EINVAL; return -1;}
if (strlen(path) > UNIX_PATH_MAX) {errno = E2BIG; return -1;}
if (fnmatch("./tmp/*.sck",path,FNM_PATHNAME)) {errno = EINVAL; return -1;}
if (ntrial<1 || ntrial>MAXTRIAL) {errno = EINVAL; return -1;}
if (k<1 || k>MAXSEC) {errno = EINVAL; return -1;}
strncpy(sa.sun_path, path,UNIX_PATH_MAX);
sa.sun_family = AF_UNIX;
ec_meno1(fd=socket(AF_UNIX,SOCK_STREAM,0));
for (prove=0;prove<ntrial;prove++){
if (!connect(fd,(struct sockaddr*)&sa, sizeof(sa)))
return fd;
sleep(k);
}
close(fd);
return -1;
}
manda e riceve i messaggi con send e receive:
int sendMessage(int sc, message_t *msg){
int n;
fprintf(stderr,"send: %d\n",sc);
ec_null(msg);
if ((n = write(sc, &(msg->type), sizeof(char))) < sizeof(char))
return -1;
n = write(sc,&(msg->length),sizeof(unsigned int));
ec_meno1(n);
if (n < sizeof(unsigned int))
return -1;
if (&(msg->length) == 0)
return n;
if ((n = write(sc,msg->buffer,msg->length)) < msg->length)
return -1;
return n;
}
int receiveMessage(int sc, message_t * msg){
unsigned int lung;
ec_null(msg);
fprintf(stderr,"receive: %d\n",sc);
switch (lung = read(sc,&(msg->type),sizeof(char))){
case 0:
errno = ENOTCONN;
return -1;
case -1:
return -1;
default :
break;
}
lung=0;
while ((lung += read(sc,&(msg->length),sizeof(unsigned int))) < sizeof(unsigned int))
switch(lung){
case 0:
errno = ENOTCONN;
return -1;
case -1:
return -1;
}
while ((lung += read(sc,msg->buffer,msg->length)) < msg->length)
switch(lung){
case 0:
errno = ENOTCONN;
return -1;
case -1:
return -1;
}
return lung;
}
Ok, dopo avervi fatto vedere il codice un po' lunghetto... Ripeto che i messaggi sono formattati e inviati correttamente, quindi non è un problema della sendMessage. Posso dire anche che non dovrebbe essere nemmeno un problema della receiveMessage in quanto se faccio un programma con un server e un client, senza thread worker, il programma funziona. Non dovrebbe essere un problema delle funzioni (che fanno parte di una libreria). Quindi ci dev'essere qualche problema nel socket, quando viene creato il thread. Come se il thread non riuscisse a comunicare tramite il socket passatogli. Devo fare la accept dentro il thread per caso?
Sono totalmente nel panico perchè non so più dove andare a parare...
Il client invia il messaggio al server correttamente (questo posso assicurarlo, il formato del messaggio è corretto). Il server fa una accept e fa partire un thread worker... Il worker quindi fa una read sulla socket.. Qui la tragedia: il programma rimane bloccato su questa read finchè non lo termino io manualmente.
Non riesco proprio a capire il perchè... Non credo ci sia qualche errore di scrittura ma un problema proprio della struttura, quindi non state troppo a concentrarvi sul codice.. Vi metto un po' di codice e le considerazioni che ho fatto in fondo alla pagina:
SERVER:
int main(int argc, char *argv[]){
int sfd, sfd1, i,err;
pthread_t tid;
/* dichiarazioni + altre elaborazioni non importanti */
}
if ((sfd = createServerChannel(skt_bib))== -1){
fprintf(stderr,"SERVER: errore creazione socket server\n");
exit(EXIT_FAILURE);
}
while (sfd1 = acceptConnection(sfd) != -1) ){
if ((err=pthread_create(&tid,NULL,&worker,(void*)sfd1)) != 0){
fprintf(stderr,"SERVER: errore creazione worker\n");
exit(EXIT_FAILURE);
}
thread++;
}
/* altra roba non pertinente */
return 0;
}
Come vedete utilizza due funzioni: createServerChannel che crea il socket, la acceptConnetion è semplicemente una accept. Comunque ecco il codice:
int createServerChannel(char* path){
int s;
struct sockaddr_un sa;
if (path == NULL) {errno = EINVAL; return -1;}
if (strlen(path) > UNIX_PATH_MAX) {errno = E2BIG; return -1;}
if (fnmatch("./tmp/*.sck",path,FNM_PATHNAME)) {errno = EINVAL; return -1;}
strncpy(sa.sun_path, path, UNIX_PATH_MAX);
sa.sun_family = AF_UNIX;
ec_meno1(s=socket(AF_UNIX,SOCK_STREAM,0));
if (bind(s,(struct sockaddr *)&sa,sizeof(sa)) == -1) {
ec_meno1(closeServerChannel(path,s));
return -1;
}
if (listen(s,SOMAXCONN) == -1) {
ec_meno1(closeServerChannel(path,s));
return -1;
}
return s;
}
int acceptConnection(int s){
int c = accept(s,NULL,0);
return c;
}
Dopo aver accettato la connessione esegue il thread worker che rimane bloccata subito su una receive (la funzione la metto alla fine del post):
void* worker(void* arg){
int sfd = (int) arg;
message_t* msg = malloc(sizeof(message_t));
if (receiveMessage(sfd,msg) == -1){
fprintf(stderr,"SERVER: errore ricezione messaggio");
pthread_exit(0);
}
}
Ora il client:
int main(int argc, char *argv[]){
int i, j, csfd;
int k = 0;
FILE* fd;
int len = 0;
/* roba inutile */
while (!feof(fd)){
fgets(bib_name,100,fd);
j=0;
while ((bib_name[j] != '\n') && (j<strlen(bib_name)))
j++;
if (bib_name[j] == '\n')
bib_name[j] = '\0';
sprintf(addr,"./tmp/%s.sck",bib_name);
if ((csfd=openConnection(addr,NTRIAL,NSEC)) == -1 ){
fprintf(stderr,"CLIENT: errore apertura socket\n");
exit(EXIT_FAILURE);
}printf("CLIENT: %d\n",csfd);
if ((sendMessage(csfd,out)) == -1){
fprintf(stderr,"CLIENT: errore invio messaggio\n");
exit(EXIT_FAILURE);
}
if (receiveMessage(csfd,in) == -1){
fprintf(stderr,"CLIENT: errore ricezione messaggio\n");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
anche qui ho lasciato le robe che presumo importanti per capire l'errore. Il client apre la connessione al socket con la openConnection:
int openConnection(char* path, int ntrial, int k){
int prove, fd;
struct sockaddr_un sa;
if (path == NULL) {errno = EINVAL; return -1;}
if (strlen(path) > UNIX_PATH_MAX) {errno = E2BIG; return -1;}
if (fnmatch("./tmp/*.sck",path,FNM_PATHNAME)) {errno = EINVAL; return -1;}
if (ntrial<1 || ntrial>MAXTRIAL) {errno = EINVAL; return -1;}
if (k<1 || k>MAXSEC) {errno = EINVAL; return -1;}
strncpy(sa.sun_path, path,UNIX_PATH_MAX);
sa.sun_family = AF_UNIX;
ec_meno1(fd=socket(AF_UNIX,SOCK_STREAM,0));
for (prove=0;prove<ntrial;prove++){
if (!connect(fd,(struct sockaddr*)&sa, sizeof(sa)))
return fd;
sleep(k);
}
close(fd);
return -1;
}
manda e riceve i messaggi con send e receive:
int sendMessage(int sc, message_t *msg){
int n;
fprintf(stderr,"send: %d\n",sc);
ec_null(msg);
if ((n = write(sc, &(msg->type), sizeof(char))) < sizeof(char))
return -1;
n = write(sc,&(msg->length),sizeof(unsigned int));
ec_meno1(n);
if (n < sizeof(unsigned int))
return -1;
if (&(msg->length) == 0)
return n;
if ((n = write(sc,msg->buffer,msg->length)) < msg->length)
return -1;
return n;
}
int receiveMessage(int sc, message_t * msg){
unsigned int lung;
ec_null(msg);
fprintf(stderr,"receive: %d\n",sc);
switch (lung = read(sc,&(msg->type),sizeof(char))){
case 0:
errno = ENOTCONN;
return -1;
case -1:
return -1;
default :
break;
}
lung=0;
while ((lung += read(sc,&(msg->length),sizeof(unsigned int))) < sizeof(unsigned int))
switch(lung){
case 0:
errno = ENOTCONN;
return -1;
case -1:
return -1;
}
while ((lung += read(sc,msg->buffer,msg->length)) < msg->length)
switch(lung){
case 0:
errno = ENOTCONN;
return -1;
case -1:
return -1;
}
return lung;
}
Ok, dopo avervi fatto vedere il codice un po' lunghetto... Ripeto che i messaggi sono formattati e inviati correttamente, quindi non è un problema della sendMessage. Posso dire anche che non dovrebbe essere nemmeno un problema della receiveMessage in quanto se faccio un programma con un server e un client, senza thread worker, il programma funziona. Non dovrebbe essere un problema delle funzioni (che fanno parte di una libreria). Quindi ci dev'essere qualche problema nel socket, quando viene creato il thread. Come se il thread non riuscisse a comunicare tramite il socket passatogli. Devo fare la accept dentro il thread per caso?