首页 > 代码库 > 几种并发服务器模型的实现:多线程,多进程,select,poll,epoll

几种并发服务器模型的实现:多线程,多进程,select,poll,epoll

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

 

客户端使用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.并发多线程服务器

#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.多线程服务器模型:

 

#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

  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 <poll.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 static void do_service(int); 21 int listenf(); 22 void handle(int signum) 23 { 24     printf("hello\n"); 25 } 26 static void do_poll(int); 27  28 int main(int argc, const char *argv[]) 29 { 30     if(signal(SIGPIPE, handle) == SIG_ERR) 31         ERR_EXIT("signal"); 32     int listenfd = listenf(); 33     do_poll(listenfd); 34     close(listenfd); 35     return 0; 36 } 37  38 int listenf() 39 { 40     int listenfd = socket(AF_INET, SOCK_STREAM, 0);//准备一个socketfd 41     if(listenfd == -1 ) 42         ERR_EXIT("listen"); 43  44     int on = 1; 45     if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)//setsockopt设置端口复用 46     { 47         close(listenfd); 48         ERR_EXIT("setsockopt"); 49     } 50  51     struct sockaddr_in seraddr; 52     seraddr.sin_family = AF_INET; 53     seraddr.sin_port = htons(8888); 54     seraddr.sin_addr.s_addr = htonl(INADDR_ANY); 55     socklen_t len = sizeof(seraddr); 56     if(bind(listenfd, (struct sockaddr*)&seraddr, len) == -1)//监听socket端口, 57     { 58         close(listenfd); 59         ERR_EXIT("bind"); 60     } 61  62     if(listen(listenfd, 6) == -1) 63     { 64         close(listenfd); 65         ERR_EXIT("listen"); 66     } 67     return listenfd; 68 } 69  70 void do_poll(int fd) 71 { 72     struct pollfd pfd[MAXLEN];//设置的最大连接数,存放结构体信息 73     char recvbuf[1024] = {0}; 74     int i; 75     for(i = 0; i < MAXLEN; ++i) 76         pfd[i].fd = -1; 77  78     pfd[0].fd = fd; 79     pfd[0].events = POLLIN;//将监听连接的描述符防止数组开头 80  81     int nready; 82     int maxi = 0; 83     while(1) 84     { 85         nready = poll(pfd, maxi+1, -1);//轮询的是有效数组长度,不能少1 86         if(nready == -1) 87         { 88             ERR_EXIT("select"); 89         } 90  91         if(pfd[0].revents & POLLIN)//有客户端请求连接 92         { 93             int clifd = accept(fd, NULL, NULL); 94             if(clifd == -1) 95                 ERR_EXIT("accept"); 96             for(i = 1; i < MAXLEN; ++i) 97             {  98                 if(pfd[i].fd == -1) 99                 {100                     pfd[i].fd = clifd;101                     pfd[i].events = POLLIN;102                     break;103                 }104             }105             if(i > maxi)106                 maxi = i;  107             --nready;108         }109 110         for(i = 1; i <= maxi; ++i)111         {112             if(pfd[i].fd == -1)113                 continue;114 115             if( pfd[i].revents & POLLIN)116             {117                 int n = read(pfd[i].fd, recvbuf, 1024);118                 if(n == -1)119                     ERR_EXIT("read");120                 else if(n == 0)//客户端退出,则从集合中清除121                 {122                     printf("%d close\n", pfd[i].fd);123                     close(pfd[i].fd); 124                     pfd[i].fd = -1;125                     continue;126                 }127                 write(pfd[i].fd, recvbuf, strlen(recvbuf));128                 memset(recvbuf, 0, 1024);129 130                 if(--nready < 0)131                     break;132             }133         }134     }135 }

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             }else100             {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                 }else115                 {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 }

 

 

 

.poll服务器模型: