http://www.zyfforlinux.cc/2015/02/11/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%9F%E4%B8%80%E4%BA%8B%E4%BB%B6%E6%BA%90/
事件源有哪些?
- 定时器的超时事件(本质上依靠信号SIGALARM)
- 信号
- 数据读
- 数据写
- 网络异常
网络编程中的一些常见的事件,这些事件各自又各自的独特处理方式,和程序主循环是不同的执行线路,
显然信号处理函数要尽快处理结束,避免后续的信号被屏蔽,所以信号处理函数要尽可能的短,那么主要
信号处理函数的主要逻辑就需要放到主循环中所以就有了统一事件源一说,意思就是将信号也当做是像数
据读/写一样的事件放到主循环中处理这种事件的业务逻辑。
如何统一处理?
既然需要统一事件源,那么该如何去实施呢,先说一个简单的实现思路,更复杂的可以参考其他的设计,
比如xinetd或是libevent的内部实现,简单的实现思路就是当信号发生的时候进入信号处理函数,信号处理
函数只是简单的发送到管道,IO复用程序会监听管道的另一头如果有数据到来就进入主循环内获取信号值,
根据不同的信号值来处理对应的业务逻辑。
代码实现
下面是一段统一事件源的代码示例,下面只是列出主要的实现逻辑
//创建一个双向管道用于通知信号值
ret = socketpair(PF_UNIX,SOCK_STREAM,0,sig_pipefd);
assert(ret != -1);
setnonblocking(sig_pipefd[1]); //设置为非阻塞
addfd(epollfd,sig_pipefd[0]); //加入到epoll监听的事件集中
//信号处理函数,多线程,多进程环境中为了可重入要保存errno
void sig_handler(int sig)
{
int save_errno = errno;
int msg = sig;
send(sig_pipefd[1],(char *)&msg,1,0); //发送信号值
errno = save_errno;
}
//epoll返回的事件集
sockfd = events[i].events.data.fd;
if((sockfd == sig_pipefd[0]) && (events[i].events & EPOLLIN)) //信号事件可读
{
int sig;
char signals[1024];
ret = recv(sig_pipefd[0],signals,sizeof(signals),0); //接收信号信号的大小是一个字节
if(-1 == ret)
{
continue;
}
else if(ret == 0)
{
continue;
}
else
{
for(int i = 0;i < ret;++i)
{
switch(signals[i]) //recv可能一次会接受到多个信号,并存放到signals[]数组中
{
case SIGCHLD:
{
//主要的业务逻辑
break;
}
case SIGALARM:
{
//业务逻辑
break;
}
///可以case 你要的任一信号
default:
break;
}
}
}
浙公网安备 33010602011771号