Created
May 11, 2016 03:11
-
-
Save limboinf/ba2a7e901c9a06f3c7ba70899be9fe35 to your computer and use it in GitHub Desktop.
统一事件源
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//统一事件源 | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <sys/epoll.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <string.h> | |
#include <assert.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <arpa/inet.h> | |
#include <netinet/in.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <signal.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; | |
} | |
/*添加epollfd*/ | |
void addfd(int epollfd, int fd) | |
{ | |
epoll_event event; | |
event.data.fd = fd; | |
event.events = EPOLLIN|EPOLLET; | |
epoll_ctl(int epollfd, EPOLL_CTL_ADD, fd, &event); | |
setnonblocking(fd); | |
} | |
/*信号处理函数*/ | |
void sig_handler(int sig) | |
{ | |
/*保留原来的errno,在函数最后恢复以便函数的可重入性*/ | |
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) { | |
fprintf(stderr, "usage: %s ip port\n", argv[0]); | |
return 1; | |
} | |
const char *ip = argv[1]; | |
int port = atoi(argv[2]); | |
int ret = 0; | |
struct sockaddr_in sock_addr; | |
bzero(&sock_addr, sizeof(sock_addr)); | |
sock_addr.sin_family = AF_INET; | |
sock_addr.sin_port = htons(port); | |
inet_pton(AF_INET, ip, &sock_addr.sin_addr); | |
int listenfd = socket(PF_INET, SOCK_STREAM, 0); | |
assert(listenfd>=0); | |
ret = bind(listenfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); | |
assert(ret!=-1); | |
ret = listen(listenfd, 5); | |
assert(ret!=-1); | |
epoll_event events[MAX_EVENT_NUMBER]; | |
int epfd = epoll_create(5); | |
assert(epfd!=-1); | |
addfd(epfd, listenfd); | |
/*使用socketpair创建管道,注册pipefd[0]上的可读事件*/ | |
ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd); | |
assert(ret!=-1); | |
setnonblocking(pipefd[1]); | |
addfd(epfd, pipefd[0]); | |
/*设置一些信号处理函数*/ | |
addsig(SIGHUP); | |
addsig(SIGCHLD); | |
addsig(SIGTERM); | |
addsig(SIGINT); | |
int stop_server = 0; | |
while (!stop_server) { | |
int number = epoll_wait(epfd, 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; | |
/*如果就绪的文件描述符是listenfd,则处理新连接*/ | |
if (sockfd == listenfd) { | |
struct sockaddr_in client_addr; | |
socklen_t client_addr_len = sizeof(client_addr); | |
int connfd = accept(listenfd, (struct sockaddr*)&client_addr, &client_addr_len); | |
addfd(epfd, connfd); | |
} | |
/*如果就绪的文件描述符是pipefd[0],则处理信号*/ | |
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 { | |
/*因为每个信号值占1字节,所以按字节来逐个接收信号*/ | |
for (int i=0; i<ret; ++i) { | |
switch (signals[i]) { | |
case SIGCHLD: | |
case SIGHUP: | |
{ | |
continue; | |
} | |
case SIGTERM: | |
case SIGINT: | |
{ | |
stop_server = 1; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
printf("close fds\n"); | |
close(listenfd); | |
close(pipefd[1]); | |
close(pipefd[0]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment