几种并发服务器模型的实现:多线程,多进程,select,poll,epoll
2014-07-31 00:18
1041 查看
客户端使用select模型:
1.并发多进程服务器
2.多线程服务器模型:
3.select服务器模型:
4
5.epoll服务器模型:
.poll服务器模型:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/select.h> #include <signal.h> #define ERR_EXIT(m) \ do { \ perror(m);\ exit(EXIT_FAILURE);\ }while(0) static void do_client(int fd) { char recvbuf[MAXLINE + 1] = {0}; char sendbuf[MAXLINE + 1] = {0}; fd_set reade, ready; FD_ZERO(&reade); int fd_stdin = fileno(stdin); FD_SET(fd_stdin, &reade); FD_SET(fd, &reade); int fd_max = (fd_stdin > fd) ? fd_stdin : fd; int ret; while(1) { ready = reade; ret = select( fd_max+1, &ready, NULL, NULL, NULL);//轮询 if(ret == -1) { if(errno == EINTR) continue; ERR_EXIT("select"); }else if(ret == 0) { continue; } if(FD_ISSET(fd_stdin, &ready)) { if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL) { close(fd); break; }else { if( -1 == write(fd, sendbuf, strlen(sendbuf))) printf("write\n"); } } if(FD_ISSET(fd, &ready)) { int nread = read(fd, recvbuf, MAXLINE); if(nread < 0) ERR_EXIT("read"); if(nread == 0)//如果没接收到消息,打印关闭描述符,退出循环 { fprintf(stdout, "fd close\n"); break; } fprintf(stdout, "receive:%s", recvbuf); } memset(recvbuf, 0, sizeof recvbuf); memset(sendbuf, 0, sizeof sendbuf); } } void handle(int signum) { printf("sigpipe\n"); } int main(int argc, const char *argv[]) { signal(SIGPIPE, SIG_IGN); int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) ERR_EXIT("socket"); struct sockaddr_in cliaddr; cliaddr.sin_family = AF_INET; cliaddr.sin_port = htons(8888); cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); socklen_t len = sizeof cliaddr; int ret ; if((ret = connect(fd, (struct sockaddr*)&cliaddr, len)) == -1) { close(fd); ERR_EXIT("connect"); } do_client(fd); close(fd); return 0; }
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服务器模型:
#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 <signal.h> #include <sys/select.h> #define MAXLEN 1024 #define ERR_EXIT(m) \ do { \ perror(m);\ exit(EXIT_FAILURE);\ }while(0) int listenf();//封装了网络socket的socekt,bind,listen函数,返回监听的socket描述符 void handle(int signum)//SIGPIPE(子进程结束)的信号的处理 { printf("hello\n"); } static void do_select(int); int main(int argc, const char *argv[]) { if(signal(SIGPIPE, handle) == SIG_ERR) ERR_EXIT("signal"); int listenfd = listenf(); do_select(listenfd); 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; } void do_select(int fd) { //struct sockaddr_in cliaddr; //memset(&cliaddr, 0, sizeof(cliaddr));//此处不需要客户端的地址信息 fd_set set; fd_set rset; FD_ZERO(&rset); FD_SET(fd, &rset); int nready; int fd_set[MAXLEN]; int i; for(i = 0;i < MAXLEN; ++i) fd_set[i] = -1; fd_set[0] = fd; int maxi = fd;//初始最大轮询fd是监听的fd int arrlen = 1;//表示数组长度 char recvbuf[1024] = {0}; while(1) { set = rset; nready = select(maxi+1, &set, NULL, NULL, NULL); if(nready == -1) { ERR_EXIT("select"); } if(FD_ISSET(fd, &set))//查看书否有新的客户端请求 { int clifd = accept(fd, NULL, NULL); if(clifd == -1) ERR_EXIT("accept"); for(i = 1; i < MAXLEN; ++i) { if(fd_set[i] == -1) { fd_set[i] = clifd; break; } } FD_SET(clifd, &rset); if(clifd > maxi) maxi = clifd; arrlen++; --nready; } for(i = 1; i < arrlen; ++i)//轮询数据连接 { int set_fd = fd_set[i]; if(FD_ISSET(set_fd, &set)) { int n = read(set_fd, recvbuf, 1024); if(n == -1) ERR_EXIT("read"); else if(n == 0)//客户端退出, { FD_CLR(set_fd, &rset); close(set_fd); fd_set[i] = -1; arrlen--; } write(set_fd, recvbuf, strlen(recvbuf)); memset(recvbuf, 0, 1024); if(--nready < 0) break; } } } }
4
#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 <signal.h> #include <poll.h> #define MAXLEN 1024 #define ERR_EXIT(m) \ do { \ perror(m);\ exit(EXIT_FAILURE);\ }while(0) static void do_service(int); int listenf(); void handle(int signum) { printf("hello\n"); } static void do_poll(int); int main(int argc, const char *argv[]) { if(signal(SIGPIPE, handle) == SIG_ERR) ERR_EXIT("signal"); int listenfd = listenf(); do_poll(listenfd); 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; } void do_poll(int fd) { struct pollfd pfd[MAXLEN];//设置的最大连接数,存放结构体信息 char recvbuf[1024] = {0}; int i; for(i = 0; i < MAXLEN; ++i) pfd[i].fd = -1; pfd[0].fd = fd; pfd[0].events = POLLIN;//将监听连接的描述符防止数组开头 int nready; int maxi = 0; while(1) { nready = poll(pfd, maxi+1, -1);//轮询的是有效数组长度,不能少1 if(nready == -1) { ERR_EXIT("select"); } if(pfd[0].revents & POLLIN)//有客户端请求连接 { int clifd = accept(fd, NULL, NULL); if(clifd == -1) ERR_EXIT("accept"); for(i = 1; i < MAXLEN; ++i) { if(pfd[i].fd == -1) { pfd[i].fd = clifd; pfd[i].events = POLLIN; break; } } if(i > maxi) maxi = i; --nready; } for(i = 1; i <= maxi; ++i) { if(pfd[i].fd == -1) continue; if( pfd[i].revents & POLLIN) { int n = read(pfd[i].fd, recvbuf, 1024); if(n == -1) ERR_EXIT("read"); else if(n == 0)//客户端退出,则从集合中清除 { printf("%d close\n", pfd[i].fd); close(pfd[i].fd); pfd[i].fd = -1; continue; } write(pfd[i].fd, recvbuf, strlen(recvbuf)); memset(recvbuf, 0, 1024); if(--nready < 0) break; } } } }
5.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 <signal.h> #include <sys/epoll.h> #define MAXLEN 1024 #define ERR_EXIT(m) \ do { \ perror(m);\ exit(EXIT_FAILURE);\ }while(0) int listenf(); static void do_epoll(int); int main(int argc, const char *argv[]) { int listenfd = listenf(); do_epoll(listenfd); 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; } void do_epoll(int fd) { char recvbuf[MAXLEN] = {0}; int epollfd = epoll_create(2048);//设置的最大连接数 if(epollfd == -1) ERR_EXIT("epoll_create"); struct epoll_event ev; ev.data.fd = fd; ev.events = EPOLLIN; if(epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)//加入轮询 ERR_EXIT("epoll_ctl_add"); struct epoll_event events[2048];//数组在epoll_wait返回结果的时候使用 int ret; int i;//在下面while的for循环中遍历使用 int rfd; int clientfd; int nread; while(1) { ret = epoll_wait(epollfd, events, 2048, -1); if(ret == -1) ERR_EXIT("epoll_wait"); for(i = 0; i < ret; ++i ) { rfd = events[i].data.fd; if(rfd == fd) { if((clientfd = accept(fd, NULL, NULL)) == -1) ERR_EXIT("accept"); ev.data.fd = clientfd; ev.events = EPOLLIN; if(epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev) == -1) ERR_EXIT("epoll_ctl"); }else { int nread = read(rfd, recvbuf, MAXLEN); if(nread == -1) { if(errno == EINTR) continue; ERR_EXIT("read"); }else if( nread == 0)//客户端退出,从epoll轮询中删除 { printf("%d fd close\n", rfd); ev.data.fd = rfd; ev.events = EPOLLIN; if(epoll_ctl(epollfd, EPOLL_CTL_DEL, rfd, &ev) == -1) ERR_EXIT("epoll_ctl"); }else { if(write(rfd, recvbuf, strlen(recvbuf)) == -1) ERR_EXIT("write"); memset(recvbuf, 0, MAXLEN); } } } } close(epollfd); }
.poll服务器模型:
相关文章推荐
- 几种并发服务器模型的实现:多线程,多进程,select,poll,epoll
- 几种并发服务器模型的实现:多线程,多进程,select,poll,epoll - rail
- Linux Socket 多并发服务器开源代码:xSocketd 实现PPC/TPC/SELECT/POLL/EPOLL
- 几种典型的服务器网络编程模型归纳( select poll epoll)
- 几种典型的服务器网络编程模型归纳(select poll epoll)
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
- 几种并发服务器模型的实现
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型
- Select I/O模型来实现一个并发处理多个客户端的TCP服务器
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型
- Select I/O模型来实现一个并发处理多个客户端的TCP服务器 <转>
- 使用Select I/O模型来实现一个并发处理多个客户端的TCP服务器
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型