2010-01-25 20 views
6

我正在研究一個包含多個服務器套接字的應用程序,每個服務器套接字在獨特的線程中運行。
一個外部實用程序(腳本)由其中一個線程調用。該腳本調用將消息發送到其中一個服務器套接字的實用程序(客戶端)。在C客戶端服務器應用程序中,socket()返回0

最初,我使用system()來執行這個外部腳本,但是我們不能使用它,因爲我們必須確保服務器套接字在被分叉以執行外部腳本的孩子中關閉。
我現在自己撥打fork()execvp()。我fork()然後在小孩我關閉所有的服務器套接字,然後調用execvp()執行該腳本。

現在,所有這些工作正常。問題是有時腳本會向服務器應用程序報告錯誤。該腳本通過調用另一個打開TCP套接字併發送適當數據的應用程序(客戶端)來發送這些錯誤。我的問題是客戶端應用程序獲得socket()系統調用返回的值0

注意:只有在使用我的forkExec()函數調用腳本/客戶端應用程序時,纔會發生此問題。如果手動調用腳本/客戶端應用程序,則socket()調用執行得當,並且事情正常工作。

基於這些信息我懷疑這是在我的fork()execvp()代碼下面的東西...任何想法?

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

客戶端應用程序代碼:

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

上述呼叫返回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
操作系統:Linux
拱:ARM32
內核:2.6.26

+1

你能發佈調用socket()的代碼嗎? – abc 2010-01-25 20:00:13

+1

不知道你的套接字發生了什麼。如果我指出你可以更簡單地聲明你的參數,可能對你有幫助:const char * progArgs [] = {「/ path_to_script」,arg,NULL}; - 無需分配和複製,只需在調用execvp時使用正確指針的數組即可。 – VoidPointer 2010-01-25 20:12:34

回答

9

插座()返回-1錯誤

返回0意味着插座()成功,給你文件描述符0。我懷疑,你必須關閉文件描述符的一個具有文件描述符。 0,一旦它關閉,下一次調用函數分配一個文件描述符將返回fd 0,因爲它是可用的

+0

是的,這就是我懷疑的。但是,不,我沒有做過那樣的事情。 – 2010-01-25 20:23:13

+0

它返回0(如你的問題所述)還是返回一個負值(如你的代碼示例檢查)?重申一下,如果fd 0可用,返回0是完全合法的。 – 2010-01-25 20:25:06

+0

它返回零。我明白0是一個有效的fd。這裏的問題必須與我的forkExec()函數有關,因爲如果我更改爲使用system()套接字返回> 0.不幸的是,我不能使用system()調用。 – 2010-01-25 20:34:41

1

不要忘記調用的 「明顯的問題模式」

waitpid() 

結束。我在這裏假設了一下,但是你沒有對fork()調用返回的pid做任何事情。 ( - :

+0

是的,我已經註冊了一個執行waitpid()來清理殭屍的SIGCHLD處理程序。無論如何感謝:) – 2010-01-25 20:22:33

4

值爲0的套接字是好的,這意味着stdin被關閉,這將使fd 0可供重用 - 例如通過套接字。

機率是您在forkExec()子路徑(XMLSocket/ServerFd)中關閉的文件描述符之一e tc。)是fd 0。這將在fd 0關閉時啓動子進程,當從命令行運行應用程序時不會發生這種情況,因爲fd 0已經作爲shell的stdin打開。

如果你希望你的插座不0,1或2(標準輸入/輸出/錯誤)調用您的forkExec()函數以下的所有收盤後()調用

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

} 

檢查插座返回-1意味着發生錯誤。

+0

但爲什麼是stdin被關閉?爲什麼要故意這樣做? – 2010-01-25 20:34:17

+2

這很常見(雖然他們經常被重定向到/ dev/null,如上面的代碼所示),並且關閉後臺/守護進程中不需要的所有fd,這是我猜父進程所需要的。 – nos 2010-01-25 20:38:08

0

正如在另一條評論中提到的,你真的不應該關閉0,1或2(stdin/out/err),你可以進行一次檢查以確保你不關閉它們,所以它不會被分配作爲新的fd`s當你要求一個新的插座

相關問題