system是一個使用簡單,設計複雜的程式。它主要包含fork exec waitpid三個步驟。下來我來還原樓主的錯誤:程式A:/* socksrv.c*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h> /* for struct sockaddr_in*/#define BACKLOG 10#define MYPORT 4000int main(){ char *addr; int sockfd; int new_fd; struct sockaddr_in my_addr, their_addr; int res; int sin_size; char *buf; /* 取得套接字描述符*/ sockfd = socket(AF_INET, /* domain*/ SOCK_STREAM, /* type*/ 0); /* protocol*/ if (sockfd == -1) { perror("socket"); exit(1); } /* Init sockaddr_in */ my_addr.sin_family = AF_INET; /* 注意: 應使用主機位元組順序*/ my_addr.sin_port = htons(MYPORT); /* 注意: 應使用網路位元組順序*/ my_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 使用自己的 IP 地址 */ bzero(&(my_addr.sin_zero), 8); /* 結構的其餘的部分須置 0*/ /* 指定一個套接字使用的地址及埠*/ res = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)); if (res == -1) { perror("bind"); exit(1); } /* 監聽請求, 等待連線*/ res = listen(sockfd, BACKLOG); /* 未經處理的連線請求佇列可容納的最大數目*/ if (res == -1) { perror("listen"); exit(1); }system("./hello&"); /* 接受對方的連線請求, 建立連線,返回一個新的連線描述符. * 而第一個套接字描述符仍在你的機器上原來的埠 listen() */ sin_size = sizeof(struct sockaddr_in); new_fd = accept(sockfd, (void *)&their_addr, &sin_size); buf = (char *)malloc(255); if (buf == NULL) { printf("malloc failed\n"); exit(1); } /* 接受對方發來的資料*/ res = recv(new_fd, buf, 255, 0); if (res == -1) { perror("recv()"); exit(1); } /* 關閉本次連線*/ close(new_fd); /* 關閉系統監聽*/ close(sockfd); printf("recv data:%s\n", buf); free(buf); return 0;}程式B:hello,在主程式中用system("./hello&)呼叫。#include <stdlib.h>int main(){ while(1){ sleep(1000); }return 0;}編譯後執行程式A。我們可以在其它終端視窗看到 ./A ./hello正在執行,netstat -a 看到,tcp 4000埠被 佔用。我們用Ctrl+c中斷程式A模擬樓主的崩潰操作。這時,再在其它終端視窗看看,./A沒有了。./hello還在執行。netstat -a看到。4000埠還在佔用。這時再次執行./A,提示bind: Address already in use而退出。情況就是這樣。因為執行system時,系統會fork一個A的子程序,再去執行B.當你的A崩潰以後,它的一個子程序實際上還在執行,它開啟的埠,檔案,等還在使用。所以再次執行A時,由於自定的互斥機制而退出。如:再次繫結埠時提示埠已在使用。殺死B後,A的子程序結束,它的資源釋放,所以才能再次執行A。我建議樓主使用exec系列函式來啟動B。
system是一個使用簡單,設計複雜的程式。它主要包含fork exec waitpid三個步驟。下來我來還原樓主的錯誤:程式A:/* socksrv.c*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h> /* for struct sockaddr_in*/#define BACKLOG 10#define MYPORT 4000int main(){ char *addr; int sockfd; int new_fd; struct sockaddr_in my_addr, their_addr; int res; int sin_size; char *buf; /* 取得套接字描述符*/ sockfd = socket(AF_INET, /* domain*/ SOCK_STREAM, /* type*/ 0); /* protocol*/ if (sockfd == -1) { perror("socket"); exit(1); } /* Init sockaddr_in */ my_addr.sin_family = AF_INET; /* 注意: 應使用主機位元組順序*/ my_addr.sin_port = htons(MYPORT); /* 注意: 應使用網路位元組順序*/ my_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 使用自己的 IP 地址 */ bzero(&(my_addr.sin_zero), 8); /* 結構的其餘的部分須置 0*/ /* 指定一個套接字使用的地址及埠*/ res = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)); if (res == -1) { perror("bind"); exit(1); } /* 監聽請求, 等待連線*/ res = listen(sockfd, BACKLOG); /* 未經處理的連線請求佇列可容納的最大數目*/ if (res == -1) { perror("listen"); exit(1); }system("./hello&"); /* 接受對方的連線請求, 建立連線,返回一個新的連線描述符. * 而第一個套接字描述符仍在你的機器上原來的埠 listen() */ sin_size = sizeof(struct sockaddr_in); new_fd = accept(sockfd, (void *)&their_addr, &sin_size); buf = (char *)malloc(255); if (buf == NULL) { printf("malloc failed\n"); exit(1); } /* 接受對方發來的資料*/ res = recv(new_fd, buf, 255, 0); if (res == -1) { perror("recv()"); exit(1); } /* 關閉本次連線*/ close(new_fd); /* 關閉系統監聽*/ close(sockfd); printf("recv data:%s\n", buf); free(buf); return 0;}程式B:hello,在主程式中用system("./hello&)呼叫。#include <stdlib.h>int main(){ while(1){ sleep(1000); }return 0;}編譯後執行程式A。我們可以在其它終端視窗看到 ./A ./hello正在執行,netstat -a 看到,tcp 4000埠被 佔用。我們用Ctrl+c中斷程式A模擬樓主的崩潰操作。這時,再在其它終端視窗看看,./A沒有了。./hello還在執行。netstat -a看到。4000埠還在佔用。這時再次執行./A,提示bind: Address already in use而退出。情況就是這樣。因為執行system時,系統會fork一個A的子程序,再去執行B.當你的A崩潰以後,它的一個子程序實際上還在執行,它開啟的埠,檔案,等還在使用。所以再次執行A時,由於自定的互斥機制而退出。如:再次繫結埠時提示埠已在使用。殺死B後,A的子程序結束,它的資源釋放,所以才能再次執行A。我建議樓主使用exec系列函式來啟動B。