2010-01-25 14 views
6

Sto lavorando a un'applicazione che contiene diversi socket server che vengono eseguiti in un thread univoco.
Un'utilità esterna (script) viene chiamata da uno dei thread. Questo script chiama un'utilità (client) che invia un messaggio a uno dei socket del server.socket() restituisce 0 nell'applicazione client C client

Inizialmente, stavo usando system() per eseguire questo script esterno, ma non potevamo usarlo perché dovevamo assicurarci che i socket del server fossero chiusi nel child che era stato biforcato per eseguire lo script esterno.
Io chiamo ora fork() e execvp() me stesso. I fork() e poi nel bambino chiudo tutti i socket del server e quindi chiamo execvp() per eseguire lo script.

Ora, tutto funziona bene. Il problema è che a volte lo script segnala errori all'app del server. Lo script invia questi errori chiamando un'altra applicazione (client) che apre un socket TCP e invia i dati appropriati. Il mio problema è che l'app client ottiene un valore di 0 restituito dalla chiamata di sistema socket().

NOTA: questo si verifica SOLO quando l'app script/client viene chiamata utilizzando la funzione forkExec(). Se l'app script/client viene chiamata manualmente, la chiamata socket() viene eseguita correttamente e le cose funzionano correttamente.

Sulla base di tali informazioni, sospetto che sia qualcosa nel mio codice execvp() di fork() sotto ... Qualche idea?

void forkExec() 
{  
    int stat; 

    stat = fork(); 
    if (stat < 0) 
    { 
     printf("Error forking child: %s", strerror(errno)); 
    } 
    else if (stat == 0) 
    { 
     char *progArgs[3]; 

     /* 
     * First, close the file descriptors that the child 
     * shouldn't keep open 
     */ 
     close(ServerFd); 
     close(XMLSocket); 
     close(ClientFd); 
     close(EventSocket); 
     close(monitorSocket); 

     /* build the arguments for script */ 
     progArgs[0] = calloc(1, strlen("/path_to_script")+1); 
     strcpy(progArgs[0], "/path_to_script"); 
     progArgs[1] = calloc(1, strlen(arg)+1); 
     strcpy(progArgs[1], arg); 
     progArgs[2] = NULL; /* Array of args must be NULL terminated for execvp() */ 

     /* launch the script */ 
     stat = execvp(progArgs[0], progArgs); 
     if (stat != 0) 
     { 
      printf("Error executing script: '%s' '%s' : %s", progArgs[0], progArgs[1], strerror(errno)); 
     } 
     free(progArgs[0]); 
     free(progArgs[1]); 
     exit(0); 
    } 

    return; 
} 

client codice app:

static int connectToServer(void) 
{ 
int socketFD = 0; 
int status; 
struct sockaddr_in address; 
struct hostent* hostAddr = gethostbyname("localhost"); 

socketFD = socket(PF_INET, SOCK_STREAM, 0); 

La chiamata restituisce sopra 0.

if (socketFD < 0) 
{ 
    fprintf(stderr, "%s-%d: Failed to create socket: %s", 
           __func__, __LINE__, strerror(errno)); 
    return (-1); 
} 

memset(&address, 0, sizeof(struct sockaddr)); 
address.sin_family = AF_INET; 
memcpy(&(address.sin_addr.s_addr), hostAddr->h_addr, hostAddr->h_length); 
address.sin_port = htons(POLLING_SERVER_PORT); 

status = connect(socketFD, (struct sockaddr *)&address, sizeof(address)); 
if (status < 0) 
{ 
    if (errno != ECONNREFUSED) 
    { 
     fprintf(stderr, "%s-%d: Failed to connect to server socket: %s", 
        __func__, __LINE__, strerror(errno)); 
    } 
    else 
    { 
     fprintf(stderr, "%s-%d: Server not yet available...%s", 
        __func__, __LINE__, strerror(errno)); 
     close(socketFD); 
     socketFD = 0; 
    } 
} 

return socketFD; 
} 

FYI
OS: Linux
Arco: ARM32
del kernel: 2.6.26

+1

Potresti pubblicare il codice che chiama socket() per favore? – abc

+1

Non ho idea di cosa sta succedendo al tuo socket. Forse è di aiuto se ti faccio notare che puoi dichiarare i tuoi argomenti molto più semplici: const char * progArgs [] = {"/ path_to_script", arg, NULL}; - Nessuna necessità di allocare e copiare, tutto ciò che serve è un array con i puntatori giusti al momento in cui si chiama execvp. – VoidPointer

risposta

9

socket() restituisce -1 in caso di errore

Un ritorno di 0 significa socket() è riuscita e ha dato si file descrittore 0. Ho il sospetto che uno dei descrittori di file di chiudere ha descrittore di file. 0 e una volta chiusa la prossima chiamata a una funzione che ha assegnato un descrittore di file restituirà fd 0 come disponibile

+0

Sì, questo è quello che sospettavo. Ma no, non ho fatto niente del genere. –

+0

Restituisce 0 (come indica la domanda) o restituisce un valore negativo (come per gli esempi di esempio del codice)? Per reiterare, un ritorno di 0 è completamente legale se fd 0 è disponibile. –

+0

restituisce zero. Capisco che 0 è un file fd valido. Il problema qui deve avere qualcosa a che fare con la mia funzione forkExec() perché se cambio di usare il sistema() il socket restituisce> 0. Sfortunatamente, non posso usare la chiamata system(). Il sistema –

1

Non dimenticare una chiamata a

waitpid() 

fine di "modalità di domanda più ovvia". Sto assumendo un po 'qui ma non stai facendo nulla con il pid restituito dalla chiamata a fork(). (-:

+0

Sì, ho già registrato un gestore SIGCHLD che esegue waitpid() per ripulire gli zombi. Grazie comunque :) –

4

Un socket con valore 0 va bene, significa che stdin è stato chiuso che renderà disponibile fd 0 per il riutilizzo -

è probabile che uno degli autori di file che si chiude nel percorso secondario forkExec() (XMLSocket/ServerFd) e tc.) era fd 0. Questo inizierà il bambino con fd 0 chiuso, cosa che non succederà quando si esegue l'app da una riga di comando, poiché fd 0 sarà già aperto come stdin della shell.

Se volete che il vostro presa per non essere 0,1 o 2 (stdin/out/err) chiamare il seguente nella funzione forkExec() dopo tutto il close() chiama

void reserve_tty() 
{ 
    int fd; 

    for(fd=0; fd < 3; fd++) 
    int nfd; 
    nfd = open("/dev/null", O_RDWR); 

    if(nfd<0) /* We're screwed. */ 
    continue; 

    if(nfd==fd) 
    continue; 

    dup2(nfd, fd); 
    if(nfd > 2) 
    close(nfd); 

} 

Verificare la presa restituendo -1, il che significa che si è verificato un errore.

+0

Ma PERCHÉ STDIN sta per essere chiuso? Perché uno vorrebbe farlo intenzionalmente? –

+2

È comune (anche se spesso vengono reindirizzati a/dev/null come mostrato nel codice sopra ora) e buona pratica per chiudere tutti i file fd non necessari in un processo background/daemon, che suppongo sia il processo genitore. – nos

0

Come è menzionato in un altro commento, non dovresti davvero chiudere 0,1 o 2 (stdin/out/err), puoi mettere un assegno per essere sicuro di non chiuderli e quindi non verrà assegnato come nuovo fd`s quando richiedi un nuovo socket