??多進程的特性是復制父進程的所有數據,這和多線程的公用內存不一樣,多進程的好處在于不容易出現一些麻煩的內存問題,多線程的互斥是一件很麻煩的事情,當然也因為這樣,多進程也擁有自己的局限性。
??利用 多進程+阻塞I/O 的方式實現不阻塞I/O,簡單來說就是每accept到一個新的連接,就創建一個子進程,通過那個子進程來單方面通信,子進程里面還是用的最簡單的阻塞I/O,這樣的話就能實現維護多用戶同時連接的問題,當然這樣還是不能實現異步I/O,想要實現異步I/O的話,可以在子進程里面創建一個子線程,主線程加子線程就可以實現異步I/O,我這里只是一個簡單的實現,前后不過花了我十幾分鐘時間,所以沒加多線程的內容。
??子進程復制了父進程的數據,所以可以利用父進程里面的套接字和sockaddr。
我這里是用的標準C寫的,沒有C/C++混寫,寫得比較丑,因為只是一個簡單的demo,所以沒有考慮代碼風格的問題
/********************************************************* * Author : crazy_mad * Last modified : 2017-01-16 15:39 * Filename : main.c * Description : *********************************************************/#include <sys/socket.h>#include <sys/types.h>#include <arpa/inet.h>#include <netinet/in.h>#include <errno.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <sys/wait.h>#include <unistd.h>#define BUF_LENGTH 256 // buf長度int main(int argc, char* argv[]){ int on = 1; int server_fd = socket(AF_INET, SOCK_STREAM, 0); // 設置socket模式,這里主要是設置的tcp和重復使用地址 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { PRintf("setsockopt error: %s/n", strerror(errno)); exit(1); } socklen_t len = sizeof(struct sockaddr_in); struct sockaddr_in server_addr, client_addr; // 客戶端、服務端地址信息 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8001); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 綁定地址 if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { printf("bind error: %s/n", strerror(errno)); exit(1); } memset(&client_addr, 0, sizeof(client_addr)); listen(server_fd, 10); while (1) { int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len); char buf[BUF_LENGTH] = { 0 }; // 創建子進程 pid_t child = fork(); int status; if (child == -1) { // 創建子進程失敗 perror("fork"); exit(EXIT_FAILURE); } else if (child == 0) { // 創建子進程成功 printf("child pid=%d ppid=%d created/n", getpid(), getppid()); int ret; while (1) { ret = recv(client_fd, buf, BUF_LENGTH, 0); if (ret <= 0) { // socket連接斷開(或其他異常) break; } printf("%s/n", buf); }; printf("child pid=%d exit!/n", getpid()); close(client_fd); // 回收客戶端套接字 exit(EXIT_SUCCESS); } else { // 子進程成功退出 //printf("parent pid=%d ppid=%d/n", getpid(), getppid()); int w = waitpid(child, &status, WUNTRACED | WCONTINUED); if (w == -1) { // 子進程退出異常 perror("waitpid"); exit(EXIT_FAILURE); } else { // 子進程正常退出 //printf("child exited/n"); } } } close(server_fd); // 回收套接字 return 0;}
新聞熱點
疑難解答