Skip to content

Instantly share code, notes, and snippets.

@limboinf
Created May 11, 2016 03:11
Show Gist options
  • Save limboinf/ba2a7e901c9a06f3c7ba70899be9fe35 to your computer and use it in GitHub Desktop.
Save limboinf/ba2a7e901c9a06f3c7ba70899be9fe35 to your computer and use it in GitHub Desktop.
统一事件源
//统一事件源
#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