2010-01-25 13 views
6

Pracuję nad aplikacją, która zawiera kilka gniazd serwera, z których każdy działa w unikalnym wątku.
Zewnętrzne narzędzie (skrypt) jest wywoływane przez jeden z wątków. Ten skrypt wywołuje narzędzie (klienta), które wysyła wiadomość do jednego z gniazd serwera.socket() zwraca 0 w aplikacji serwera klienta C

Początkowo używałem system() do wykonania tego zewnętrznego skryptu, ale nie mogliśmy tego użyć, ponieważ musieliśmy upewnić się, że gniazda serwera zostały zamknięte w potomku, które zostało rozwidlone w celu wykonania zewnętrznego skryptu.
Sam teraz nazywam się fork() i . I fork(), a następnie w systemie podrzędnym zamykam wszystkie gniazda serwera, a następnie wywołuję execvp(), aby wykonać skrypt.

Teraz wszystko działa dobrze. Problem polega na tym, że czasami skrypt zgłasza błędy w aplikacji serwera. Skrypt wysyła te błędy, wywołując inną aplikację (klienta), która otwiera gniazdo TCP i wysyła odpowiednie dane. Mój problem polega na tym, że aplikacja kliencka otrzymuje wartość 0 zwróconą przez wywołanie systemowe socket().

UWAGA: Ten parametr występuje TYLKO po wywołaniu skryptu/aplikacji klienckiej przy użyciu mojej funkcji forkExec(). Jeśli skrypt/aplikacja klienta jest wywoływana ręcznie, wywołanie socket() działa poprawnie i wszystko działa poprawnie.

Na podstawie tych informacji podejrzewam, że jest to coś w moim fork() kod execvp() poniżej ... Wszelkie pomysły?

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 kod aplikacji:

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); 

Powyższe powraca połączeń 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
Arch: arm32
Kernel: 2.6.26

+1

Czy możesz wysłać kod, który wywołuje socket(), proszę? – abc

+1

Nie mam jeszcze pojęcia, co się dzieje z twoim gniazdem. Może ci pomóc, jeśli powiem, że możesz znacznie łatwiej wypowiadać argumenty: const char * progArgs [] = {"/ path_to_script", arg, NULL}; - Nie trzeba przydzielać i kopiować, wszystko, czego potrzebujesz, to tablica z odpowiednimi wskaźnikami w czasie, gdy wywołujesz execvp. – VoidPointer

Odpowiedz

9

socket() zwraca -1 w przypadku błędu

powrotu 0 oznacza socket() udało i dał złożyć deskryptora 0. Podejrzewam, że jeden z deskryptorów plików, które po zamknięciu ma deskryptor pliku. 0 i po jego zamknięciu następne wywołanie funkcji, która przydzieliła deskryptor pliku, zwróci fd 0, ponieważ jest ona dostępna

+0

Tak, właśnie to podejrzewałem. Ale nie, nie zrobiłem czegoś takiego. –

+0

Powraca 0 (jak stwierdzi twoje pytanie), czy zwraca wartość ujemną (jak sprawdza przykładowy kod)? Aby powtórzyć, zwrot 0 jest całkowicie legalny, jeśli fd 0 jest dostępne. –

+0

Powraca zero. Rozumiem, że 0 jest prawidłowym fd. Kwestia tutaj musi mieć coś wspólnego z moją funkcją forkExec(), ponieważ jeśli zmienię by użyć gniazda systemowego() powróci> 0. Niestety, nie mogę użyć wywołania system(). –

1

Nie zapomnij zadzwonić do

waitpid() 

Koniec "oczywistej trybie zapytania". Zakładam trochę tutaj, ale nie robisz nic z pid zwrócony przez wywołanie fork(). (-:

+0

Tak, mam już zarejestrowany program obsługi SIGCHLD, który wykonuje funkcję waitpid() w celu czyszczenia zombie. Dzięki i tak :) –

4

Gniazdo o wartości 0 jest w porządku, oznacza to, że stdin został zamknięty, co spowoduje udostępnienie fd 0 do ponownego użycia - na przykład przez gniazdo.Tylko:

jest szansa na to, że zamkniesz jeden ze znaczników pliku w ścieżce podrzędnej forkExec() podrzędnej (XMLSocket/ServerFd) e tc.) to fd 0. To uruchomi dziecko z fd 0 zamkniętym, co nie stanie się, gdy uruchomisz aplikację z linii poleceń, ponieważ fd 0 będzie już otwarte jako standardowe wejście powłoki.

Jeśli chcesz, aby Twoje gniazdko nie być 0,1 lub 2 (stdin/out/err) nazywamy następujące w funkcji forkExec() Wszakże zamknięciu() wywołuje

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); 

} 

Sprawdzić gniazda return -1, co oznacza wystąpienie błędu.

+0

Ale dlaczego jest zamknięty stdin? Dlaczego ktoś chciałby robić to celowo? –

+2

Powszechne (chociaż często są przekierowywane do/dev/null, jak pokazano w powyższym kodzie) i dobra praktyka, aby zamknąć wszystkie fd, które nie są potrzebne w procesie w tle/demona, co, jak sądzę, jest procesem nadrzędnym. – nos

0

Jak wspomniano w innym komentarzu, tak naprawdę nie należy zamykać 0,1 lub 2 (stdin/out/err), można umieścić czek, aby upewnić się, że ich nie zamykasz, a więc nie zostanie przypisany jako nowe fd, gdy żądasz nowego gniazda

Powiązane problemy