标签:
可以将信号注册进pipe管道的写端,通过对读端的监听,来实现统一事件源。
#include <sys/types.h> #include <sys/socket.h> #include <sys/epoll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #include <pthread.h> #define MAX_EVENT_NUMBER 1024 static int pipefd[2]; int setnonblocking(int fd) { int old_option = fcntl(fd, F_GETFL); int new_option = old_option | O_NONBLOCK; fcntl(fd, F_SETFL, new_option); return old_option; } void addfd(int epollfd, int fd) { epoll_event event; event.data.fd = fd; event.events = EPOLLIN | EPOLLET; epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event); setnonblocking(fd); } void sig_handler(int sig) { int save_errno = errno; int msg = sig; send(pipefd[1], (char*)&msg, 1, 0); errno = save_errno; } void addsig(int sig) { struct sigaction sa; memset(&sa, ‘\0‘, sizeof(sa)); sa.sa_handler = sig_handler; sa.sa_flags != SA_RESTART; sigfillset(&sa.sa_mask); assert(sigaction(sig, &sa, NULL) != -1); } int main(int argc, char *argv[]) { if (argc <= 2) { printf("usage: %s ip port\n", basename(argv[0])); return 1; } const char *ip = argv[1]; int port = atoi(argv[2]); int ret = 0; sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; inet_pton(AF_INET, ip, &address.sin_addr); address.sin_port = htons(port); int listenfd = socket(PF_INET, SOCK_STREAM, 0); assert(listenfd >= 0); ret = bind(listenfd, (sockaddr*)&address, sizeof(address)); if (ret == -1) { printf("errno is %d\n", errno); return 1; } ret = listen(listenfd, 5); assert(ret != -1); epoll_event events[MAX_EVENT_NUMBER]; int epollfd = epoll_create(5); assert(epollfd != -1); addfd(epollfd, listenfd); ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd); assert(ret != -1); setnonblocking(pipefd[1]); addfd(epollfd, pipefd[0]); addsig(SIGHUP); addsig(SIGCHLD); addsig(SIGTERM); addsig(SIGINT); bool stop_server = false; while (!stop_server) { int number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1); if ((number < 0) && (errno != EINTR)) { printf("epoll failure\n"); break; } for (int i=0; i<number; i++) { int sockfd = events[i].data.fd; if (sockfd == listenfd) { printf("New connection is coming.\n"); sockaddr_in client_address; socklen_t client_addrlen = sizeof(client_address); int connfd = accept(listenfd, (sockaddr*)&client_address, &client_addrlen); printf("New connection established.\n"); addfd(epollfd, connfd); } else if ((sockfd == pipefd[0]) && (events[i].events & EPOLLIN)) { int sig; char signals[1024]; ret = recv(pipefd[0], signals, sizeof(signals), 0); if (ret == -1) { continue; } else if (ret == 0) { continue; } else { for (int i=0; i<ret; ++i) { switch(signals[i]) { case SIGCHLD: { printf("SIGCHLD CONTINUE\n"); continue; } case SIGHUP: { printf("SIGHUP CONTINUE\n"); continue; } case SIGTERM: { printf("SIGTERM END PROGRAM\n"); stop_server = true; break; } case SIGINT: { printf("SIGINT END PROGRAM\n"); stop_server = true; break; } } } } } else { // handle connected fd, ignore } } } printf("close fds\n"); close(listenfd); close(pipefd[1]); close(pipefd[0]); return 0; }
Makefile的文件内容:
uniserver : uniserver.cpp
g++ -o uniserver uniserver.cpp -lpthread
编译出服务器程序之后,运行服务器:
$ ./uniserver 127.0.0.1 12111 New connection is coming. New connection established. SIGTERM END PROGRAM close fds $ ./uniserver 127.0.0.1 12111 ^CSIGINT END PROGRAM close fds
运行客户端:
$ telnet 127.0.0.1 12111 Trying 127.0.0.1... Connected to localhost.localdomain (127.0.0.1). Escape character is ‘^]‘. a ^C^] telnet> quit Connection closed. $ ps ux | grep uniserver work 20265 0.0 0.0 8192 828 pts/0 S+ 23:22 0:00 ./uniserver 127.0.0.1 12111 work 20806 0.0 0.0 51132 580 pts/1 S+ 23:23 0:00 grep uniserver $ kill 20265
标签:
原文地址:http://www.cnblogs.com/charlesblc/p/5554785.html