2010-01-25 45 views
6

Tôi đang làm việc trên một ứng dụng có chứa một số ổ cắm máy chủ mà mỗi máy chủ chạy trong một chuỗi duy nhất.
Tiện ích bên ngoài (tập lệnh) được gọi bởi một trong các chủ đề. Kịch bản lệnh này gọi một tiện ích (máy khách) gửi một thông điệp đến một trong các ổ cắm máy chủ.socket() trả về 0 trong ứng dụng máy chủ ứng dụng khách C

Ban đầu, tôi đang sử dụng system() để thực thi tập lệnh bên ngoài này, nhưng chúng tôi không thể sử dụng vì chúng tôi phải đảm bảo rằng các cổng máy chủ đã được đóng trong đứa trẻ được chia nhỏ để thực thi tập lệnh bên ngoài.
Tôi hiện gọi số fork()execvp(). Tôi fork() và sau đó trong đứa trẻ tôi đóng tất cả các ổ cắm máy chủ và sau đó gọi execvp() để thực thi kịch bản.

Bây giờ, tất cả đều hoạt động tốt. Vấn đề là đôi khi kịch bản báo cáo lỗi cho ứng dụng máy chủ. Kịch bản lệnh gửi các lỗi này bằng cách gọi một ứng dụng (client) khác mở một socket TCP và gửi dữ liệu thích hợp. Vấn đề của tôi là ứng dụng khách nhận được một giá trị là 0 được trả về bởi cuộc gọi hệ thống socket().

LƯU Ý: CHỈ này xảy ra khi ứng dụng tập lệnh/ứng dụng khách được gọi bằng hàm forkExec() của tôi. Nếu ứng dụng tập lệnh/ứng dụng khách được gọi theo cách thủ công thì cuộc gọi socket() hoạt động phù hợp và mọi thứ hoạt động tốt.

Dựa trên thông tin đó, tôi nghi ngờ có gì đó trong ngã ba() mã execvp() của tôi bên dưới ... Bất kỳ ý tưởng nào?

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

Khách hàng mã ứng dụng:

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

Cuộc gọi lợi nhuận trên 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
Hệ điều hành: Linux
Arch: ARM32
Kernel: 2.6.26

+1

Bạn có thể đăng mã gọi socket() không? – abc

+1

Không có ý tưởng gì đang xảy ra với ổ cắm của bạn. Có lẽ đó là trợ giúp cho bạn nếu tôi chỉ ra rằng bạn có thể khai báo các đối số của bạn đơn giản hơn nhiều: const char * progArgs [] = {"/ path_to_script", arg, NULL}; - Không cần phải phân bổ và sao chép, tất cả những gì bạn cần là một mảng với các con trỏ thích hợp tại thời điểm bạn gọi execvp. – VoidPointer

Trả lời

9

socket() trả về -1 về lỗi

Tờ khai từ 0 có nghĩa là ổ cắm() đã thành công và đã cho bạn mô tả tập tin 0. Tôi nghi ngờ rằng một trong những mô tả tập tin mà bạn đóng có mô tả tập tin. 0 và một khi nó đóng cửa, cuộc gọi tiếp theo đến một chức năng được cấp phát một bộ mô tả tập tin sẽ trả về fd 0 vì nó có sẵn

+0

Vâng, đó là những gì tôi nghi ngờ. Nhưng không, tôi đã không làm bất cứ điều gì như thế. –

+0

Nó trả về 0 (như trạng thái câu hỏi của bạn) hoặc nó trả về một giá trị âm (như mẫu mã của bạn kiểm tra)? Để nhắc lại, trả về 0 là hoàn toàn hợp pháp nếu fd 0 khả dụng. –

+0

Nó trở về không. Tôi hiểu rằng 0 là một fd hợp lệ. Vấn đề ở đây phải có một cái gì đó để làm với hàm forkExec() của tôi bởi vì nếu tôi thay đổi để sử dụng system() socket returns> 0. Thật không may, tôi không thể sử dụng cuộc gọi system(). –

1

Đừng quên một cuộc gọi đến

waitpid() 

End của "chế độ câu hỏi rõ ràng". Tôi giả định một chút ở đây nhưng bạn không làm bất cứ điều gì với pid trở lại bởi các fork() gọi. (-:

+0

Vâng, tôi đã có một bộ xử lý SIGCHLD đăng ký thực hiện waitpid() để dọn dẹp zombie. Cảm ơn anyway :) –

4

Ổ cắm có giá trị 0 là tốt, có nghĩa là stdin đã đóng sẽ làm cho fd 0 có sẵn để tái sử dụng - chẳng hạn như bởi một ổ cắm.

cơ hội là một trong những trình mô tả mà bạn đóng trong ngã ba con đường con (XMLSocket/ServerFd) e tc.) là fd 0. Điều đó sẽ bắt đầu con với fd 0 đóng, điều này sẽ không xảy ra khi bạn chạy ứng dụng từ một dòng lệnh, vì fd 0 sẽ được mở làm stdin của trình bao.

Nếu bạn muốn ổ cắm của bạn để không phải 0,1 hoặc 2 (stdin/out/err) gọi sau đây trong() chức năng forkExec của bạn sau khi tất cả kết thúc() gọi

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

} 

Kiểm tra ổ cắm trở về -1 có nghĩa là đã xảy ra lỗi.

+0

Nhưng tại sao stdin bị đóng? Tại sao một người muốn làm điều này cố ý? –

+2

Nó phổ biến (mặc dù thường chúng được chuyển hướng đến/dev/null như được hiển thị trong mã ở trên) và thực hành tốt để đóng tất cả các fd không cần thiết trong tiến trình nền/daemon, mà tôi đoán quy trình gốc là. – nos

0

Như được đề cập trong một nhận xét khác, bạn không nên đóng 0,1 hoặc 2 (stdin/out/err), bạn có thể đặt séc để đảm bảo bạn không đóng và vì vậy nó sẽ không được chỉ định là fd mới khi bạn yêu cầu một ổ cắm mới

Các vấn đề liên quan