几种并发服务器模型的实现:多线程,多进程,select,poll,epoll
生活随笔
收集整理的這篇文章主要介紹了
几种并发服务器模型的实现:多线程,多进程,select,poll,epoll
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://www.cnblogs.com/wj9012/p/3879605.html
客戶端使用select模型:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <errno.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <arpa/inet.h> 9 #include <sys/select.h> 10 #include <signal.h> 11 12 #define ERR_EXIT(m) \ 13 do { \ 14 perror(m);\ 15 exit(EXIT_FAILURE);\ 16 }while(0) 17 18 static void do_client(int fd) 19 { 20 char recvbuf[MAXLINE + 1] = {0}; 21 char sendbuf[MAXLINE + 1] = {0}; 22 23 fd_set reade, ready; 24 FD_ZERO(&reade); 25 int fd_stdin = fileno(stdin); 26 FD_SET(fd_stdin, &reade); 27 FD_SET(fd, &reade); 28 int fd_max = (fd_stdin > fd) ? fd_stdin : fd; 29 30 int ret; 31 while(1) 32 { 33 ready = reade; 34 ret = select( fd_max+1, &ready, NULL, NULL, NULL);//輪詢 35 if(ret == -1) 36 { 37 if(errno == EINTR) 38 continue; 39 ERR_EXIT("select"); 40 }else if(ret == 0) 41 { 42 continue; 43 } 44 45 if(FD_ISSET(fd_stdin, &ready)) 46 { 47 if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL) 48 { 49 close(fd); 50 break; 51 }else 52 { 53 if( -1 == write(fd, sendbuf, strlen(sendbuf))) 54 printf("write\n"); 55 } 56 } 57 58 59 if(FD_ISSET(fd, &ready)) 60 { 61 int nread = read(fd, recvbuf, MAXLINE); 62 if(nread < 0) 63 ERR_EXIT("read"); 64 if(nread == 0)//如果沒接收到消息,打印關閉描述符,退出循環 65 { 66 fprintf(stdout, "fd close\n"); 67 break; 68 } 69 fprintf(stdout, "receive:%s", recvbuf); 70 } 71 memset(recvbuf, 0, sizeof recvbuf); 72 memset(sendbuf, 0, sizeof sendbuf); 73 } 74 } 75 void handle(int signum) 76 { 77 printf("sigpipe\n"); 78 } 79 80 int main(int argc, const char *argv[]) 81 { 82 signal(SIGPIPE, SIG_IGN); 83 int fd = socket(AF_INET, SOCK_STREAM, 0); 84 if(fd < 0) 85 ERR_EXIT("socket"); 86 87 struct sockaddr_in cliaddr; 88 cliaddr.sin_family = AF_INET; 89 cliaddr.sin_port = htons(8888); 90 cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 91 socklen_t len = sizeof cliaddr; 92 93 int ret ; 94 if((ret = connect(fd, (struct sockaddr*)&cliaddr, len)) == -1) 95 { 96 close(fd); 97 ERR_EXIT("connect"); 98 } 99 do_client(fd); 100 close(fd); 101 return 0; 102 }?
?
1.并發多進程服務器
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <arpa/inet.h> #include "rio.h"//封裝了網絡編程中的readn? writen?? readline 3個函數 #include <signal.h> #define ERR_EXIT(m) \ ????do?{ \ ????????perror(m);\ ????????exit(EXIT_FAILURE);\ ????}while(0) static?void?do_service(int?fd) { ????rio_t rt; ????rio_init(&rt, fd); ????char?recvbuf[1024] = {0}; ????int?ret; ????while(1) ????{ ????????memset(recvbuf, 0,?sizeof?recvbuf); ????????ret = rio_readline(&rt, recvbuf, 1024); ????????if(ret == 0)?? ????????{ ????????????close(fd); ????????????exit(EXIT_SUCCESS); ????????} ????????rio_writen(fd, recvbuf,?strlen(recvbuf)) ; ????} } void?handle(int?signum)//對SIGCHLD信號的處理函數 { ????while(waitpid(-1, NULL, WNOHANG) > 0); ????return?; } int?listenf();//封裝了socket,bind,listen3個函數,返回需要監聽的連接socket描述符 int?main(int?argc,?const?char?*argv[]) { ????if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)//對客戶端關閉導致的信號的處理 ????????ERR_EXIT("signal_pipe"); ????if(signal(SIGCHLD, handle) == SIG_ERR)//對子進程結束后資源的回收 ????????ERR_EXIT("signal_chld"); ????int?listenfd = listenf(); ????struct?sockaddr_in cliaddr; ????bzero(&cliaddr,?sizeof(cliaddr)); ????socklen_t cli_len =?sizeof?cliaddr; ????int?clientfd; ????while(1) ????{ ????????clientfd = accept(listenfd, (struct?sockaddr*)&cliaddr, &cli_len); ????????if(clientfd == -1)? ????????{ ????????????close(listenfd); ????????????ERR_EXIT("accept"); ????????} ????????? ????????int?pid; ????????if((pid = fork()) == -1) ????????{ ????????????ERR_EXIT("fork"); ????????}else?if(pid == 0) ????????{ ????????????close(listenfd); ????????????do_service(clientfd); ????????????exit(EXIT_SUCCESS); ????????} ????????close(clientfd); ????} ????close(listenfd); ????return?0; } int?listenf() { ????int?listenfd = socket(AF_INET, SOCK_STREAM, 0);//準備一個socketfd ????if(listenfd == -1 ) ????????ERR_EXIT("socket"); ????int?on = 1; ????if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on,?sizeof(on)) == -1)//setsockopt設置端口復用 ????{ ????????close(listenfd); ????????ERR_EXIT("setsockopt"); ????} ????struct?sockaddr_in seraddr; ????seraddr.sin_family = AF_INET; ????seraddr.sin_port = htons(8888); ????seraddr.sin_addr.s_addr = htonl(INADDR_ANY); ????socklen_t len =?sizeof(seraddr); ????if(bind(listenfd, (struct?sockaddr*)&seraddr, len) == -1)//監聽socket端口, ????{ ????????close(listenfd); ????????ERR_EXIT("bind"); ????} ????if(listen(listenfd, 6) == -1) ????{ ????????close(listenfd); ????????ERR_EXIT("listen"); ????} ????return?listenfd; } |
?2.多線程服務器模型:
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <arpa/inet.h> #include "rio.h" #include <signal.h> #include <pthread.h> #define ERR_EXIT(m) \ ????do?{ \ ????????perror(m);\ ????????exit(EXIT_FAILURE);\ ????}while(0) static?void?do_service(int?fd) { ????rio_t rt; ????rio_init(&rt, fd); ????char?recvbuf[1024] = {0}; ????int?ret; ????int?rcnt = 0; ????while(1) ????{ ????????memset(recvbuf, 0,?sizeof?recvbuf); ????????ret = rio_readline(&rt, recvbuf, 1024); ?????????if(ret == 0) ?????????{ ?????????close(fd); //???????? break; ??????????pthread_exit(NULL); ?????????} ?????????write(fd, recvbuf,?strlen(recvbuf)) ; ????} } void?handle(int?signum) { ????printf("hello\n"); } void?*pthread_func(void?*arg) { ????pthread_detach(pthread_self()); ????int?*q = (int*)arg; ???int?p = *(int*)arg; ???free(q); ?????do_service(p); ?????close(p); } int?listenf(); int?main(int?argc,?const?char?*argv[]) { ????if(signal(SIGPIPE, handle) == SIG_ERR) ????????ERR_EXIT("signal"); ????int?listenfd = listenf(); ????struct?sockaddr_in cliaddr; ????bzero(&cliaddr,?sizeof(cliaddr)); ????socklen_t cli_len =?sizeof?cliaddr; ????int?clientfd; ????while(1) ????{ ????clientfd = accept(listenfd, (struct?sockaddr*)&cliaddr, &cli_len); ????if(clientfd == -1)? ????{ ????????close(listenfd); ????????ERR_EXIT("accept"); ????} ????pthread_t tid; ????int?*p = (int*)malloc(sizeof(int)); ???*p = clientfd; ????pthread_create(&tid, NULL, pthread_func, p); ????} ????close(listenfd); ????return?0; } int?listenf() { ????int?listenfd = socket(AF_INET, SOCK_STREAM, 0);//準備一個socketfd ????if(listenfd == -1 ) ????????ERR_EXIT("listen"); ????int?on = 1; ????if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on,?sizeof(on)) == -1)//setsockopt設置端口復用 ????{ ????????close(listenfd); ????????ERR_EXIT("setsockopt"); ????} ????struct?sockaddr_in seraddr; ????seraddr.sin_family = AF_INET; ????seraddr.sin_port = htons(8888); ????seraddr.sin_addr.s_addr = htonl(INADDR_ANY); ????socklen_t len =?sizeof(seraddr); ????if(bind(listenfd, (struct?sockaddr*)&seraddr, len) == -1)//監聽socket端口, ????{ ????????close(listenfd); ????????ERR_EXIT("bind"); ????} ????if(listen(listenfd, 6) == -1) ????{ ????????close(listenfd); ????????ERR_EXIT("listen"); ????} return?listenfd; } |
?3.select服務器模型:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <errno.h> 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 #include <sys/socket.h> 9 #include <arpa/inet.h> 10 #include <signal.h> 11 #include <sys/select.h> 12 #define MAXLEN 1024 13 14 #define ERR_EXIT(m) \ 15 do { \ 16 perror(m);\ 17 exit(EXIT_FAILURE);\ 18 }while(0) 19 20 int listenf();//封裝了網絡socket的socekt,bind,listen函數,返回監聽的socket描述符 21 void handle(int signum)//SIGPIPE(子進程結束)的信號的處理 22 { 23 printf("hello\n"); 24 } 25 static void do_select(int); 26 27 int main(int argc, const char *argv[]) 28 { 29 if(signal(SIGPIPE, handle) == SIG_ERR) 30 ERR_EXIT("signal"); 31 int listenfd = listenf(); 32 do_select(listenfd); 33 close(listenfd); 34 return 0; 35 } 36 37 int listenf() 38 { 39 int listenfd = socket(AF_INET, SOCK_STREAM, 0);//準備一個socketfd 40 if(listenfd == -1 ) 41 ERR_EXIT("listen"); 42 43 int on = 1; 44 if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)//setsockopt設置端口復用 45 { 46 close(listenfd); 47 ERR_EXIT("setsockopt"); 48 } 49 50 struct sockaddr_in seraddr; 51 seraddr.sin_family = AF_INET; 52 seraddr.sin_port = htons(8888); 53 seraddr.sin_addr.s_addr = htonl(INADDR_ANY); 54 socklen_t len = sizeof(seraddr); 55 if(bind(listenfd, (struct sockaddr*)&seraddr, len) == -1)//監聽socket端口, 56 { 57 close(listenfd); 58 ERR_EXIT("bind"); 59 } 60 61 if(listen(listenfd, 6) == -1) 62 { 63 close(listenfd); 64 ERR_EXIT("listen"); 65 } 66 return listenfd; 67 } 68 69 void do_select(int fd) 70 { 71 //struct sockaddr_in cliaddr; 72 //memset(&cliaddr, 0, sizeof(cliaddr));//此處不需要客戶端的地址信息 73 fd_set set; 74 fd_set rset; 75 FD_ZERO(&rset); 76 FD_SET(fd, &rset); 77 int nready; 78 int fd_set[MAXLEN]; 79 80 int i; 81 for(i = 0;i < MAXLEN; ++i) 82 fd_set[i] = -1; 83 fd_set[0] = fd; 84 85 int maxi = fd;//初始最大輪詢fd是監聽的fd 86 int arrlen = 1;//表示數組長度 87 88 char recvbuf[1024] = {0}; 89 while(1) 90 { 91 set = rset; 92 nready = select(maxi+1, &set, NULL, NULL, NULL); 93 if(nready == -1) 94 { 95 ERR_EXIT("select"); 96 } 97 if(FD_ISSET(fd, &set))//查看書否有新的客戶端請求 98 { 99 int clifd = accept(fd, NULL, NULL); 100 if(clifd == -1) 101 ERR_EXIT("accept"); 102 for(i = 1; i < MAXLEN; ++i) 103 { if(fd_set[i] == -1) 104 { 105 fd_set[i] = clifd; 106 break; 107 } 108 } 109 FD_SET(clifd, &rset); 110 if(clifd > maxi) 111 maxi = clifd; 112 arrlen++; 113 --nready; 114 } 115 116 for(i = 1; i < arrlen; ++i)//輪詢數據連接 117 { 118 int set_fd = fd_set[i]; 119 if(FD_ISSET(set_fd, &set)) 120 { 121 int n = read(set_fd, recvbuf, 1024); 122 if(n == -1) 123 ERR_EXIT("read"); 124 else if(n == 0)//客戶端退出, 125 { 126 FD_CLR(set_fd, &rset); 127 close(set_fd); 128 fd_set[i] = -1; 129 arrlen--; 130 } 131 write(set_fd, recvbuf, strlen(recvbuf)); 132 memset(recvbuf, 0, 1024); 133 if(--nready < 0) 134 break; 135 } 136 } 137 } 138 }
4
5.epoll服務器模型:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <errno.h> 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 #include <sys/socket.h> 9 #include <arpa/inet.h> 10 #include <signal.h> 11 #include <sys/epoll.h> 12 #define MAXLEN 1024 13 14 #define ERR_EXIT(m) \ 15 do { \ 16 perror(m);\ 17 exit(EXIT_FAILURE);\ 18 }while(0) 19 20 int listenf(); 21 static void do_epoll(int); 22 23 int main(int argc, const char *argv[]) 24 { 25 int listenfd = listenf(); 26 do_epoll(listenfd); 27 close(listenfd); 28 return 0; 29 } 30 31 int listenf() 32 { 33 int listenfd = socket(AF_INET, SOCK_STREAM, 0);//準備一個socketfd 34 if(listenfd == -1 ) 35 ERR_EXIT("listen"); 36 37 int on = 1; 38 if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)//setsockopt設置端口復用 39 { 40 close(listenfd); 41 ERR_EXIT("setsockopt"); 42 } 43 44 struct sockaddr_in seraddr; 45 seraddr.sin_family = AF_INET; 46 seraddr.sin_port = htons(8888); 47 seraddr.sin_addr.s_addr = htonl(INADDR_ANY); 48 socklen_t len = sizeof(seraddr); 49 if(bind(listenfd, (struct sockaddr*)&seraddr, len) == -1)//監聽socket端口, 50 { 51 close(listenfd); 52 ERR_EXIT("bind"); 53 } 54 55 if(listen(listenfd, 6) == -1) 56 { 57 close(listenfd); 58 ERR_EXIT("listen"); 59 } 60 return listenfd; 61 } 62 63 void do_epoll(int fd) 64 { 65 char recvbuf[MAXLEN] = {0}; 66 int epollfd = epoll_create(2048);//設置的最大連接數 67 if(epollfd == -1) 68 ERR_EXIT("epoll_create"); 69 70 struct epoll_event ev; 71 ev.data.fd = fd; 72 ev.events = EPOLLIN; 73 if(epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)//加入輪詢 74 ERR_EXIT("epoll_ctl_add"); 75 76 struct epoll_event events[2048];//數組在epoll_wait返回結果的時候使用 77 int ret; 78 int i;//在下面while的for循環中遍歷使用 79 int rfd; 80 int clientfd; 81 int nread; 82 while(1) 83 { 84 ret = epoll_wait(epollfd, events, 2048, -1); 85 if(ret == -1) 86 ERR_EXIT("epoll_wait"); 87 88 for(i = 0; i < ret; ++i ) 89 { 90 rfd = events[i].data.fd; 91 if(rfd == fd) 92 { 93 if((clientfd = accept(fd, NULL, NULL)) == -1) 94 ERR_EXIT("accept"); 95 ev.data.fd = clientfd; 96 ev.events = EPOLLIN; 97 if(epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev) == -1) 98 ERR_EXIT("epoll_ctl"); 99 }else 100 { 101 int nread = read(rfd, recvbuf, MAXLEN); 102 if(nread == -1) 103 { 104 if(errno == EINTR) 105 continue; 106 ERR_EXIT("read"); 107 }else if( nread == 0)//客戶端退出,從epoll輪詢中刪除 108 { 109 printf("%d fd close\n", rfd); 110 ev.data.fd = rfd; 111 ev.events = EPOLLIN; 112 if(epoll_ctl(epollfd, EPOLL_CTL_DEL, rfd, &ev) == -1) 113 ERR_EXIT("epoll_ctl"); 114 }else 115 { 116 if(write(rfd, recvbuf, strlen(recvbuf)) == -1) 117 ERR_EXIT("write"); 118 memset(recvbuf, 0, MAXLEN); 119 } 120 } 121 } 122 } 123 close(epollfd); 124 }總結
以上是生活随笔為你收集整理的几种并发服务器模型的实现:多线程,多进程,select,poll,epoll的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 骄阳哥的痴人说梦剧情介绍
- 下一篇: C语言calloc()函数:分配内存空间