1.epoll+信号
之前用的都是epoll+多线程/线程池
现在由信号触发,基本的模型可以写为(初始化套接字之类的,以及epoll初始化省略)
while( !stop)
{
int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 );
if ( number < 0 && errno != EINTR)
{
//打印错误并退出
break;
}
for ( int i = 0; i < number; i++ )
{
int sockfd = events[i].data.fd;
if ( sockfd == listenfd )
{
//accept返回套接字加入epoll中
}
else if ( events[i].events & EPOLLIN )
{
//信号处理函数处理
}
else {
//处理其他情况
}
}
}
但是如果是信号函数想返回某些值以供分析处理的话,这样直接丢出去是不行的
可以选择用管道,但是要全双工通信,还要建立两个pipe,有没有更好的解决方法呢,答案是有
函数在这里 更详细可以查man手册
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
这个函数的功能是创建一个无名管道(就是两个套接字sv[0] sv[1]),父进程关闭sv[0],在sv[1]接收和发送,子进程关闭sv[1],在sv[0]接收发送
原本用于两个进程间通信
例子代码在这里
https://code.youkuaiyun.com/snippets/530935
我们可以通过这种方法达到目的
static int pipefd[2];
void sig_hander(int sig)
{
//保留原来的errno, 在函数最后恢复,以保证函数的可重入性
int save_errno = errno;
int msg = sig;
//通过pipefd[1]向父进程发送信息
send(pipefd[1], (char*)&msg, 1, 0);
errno = save_errno;
}
int main(int argc, char** argv)
{
//省略套接字初始化
//省略epoll初始化
//设置信号处理函数
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)
{
struct sockaddr_in client_address;
socklen_t client_addrlength = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr*)&client_address, &client_addrlength);
addfd(epollfd, connfd);
}
//如果文件描述符是pipefd[0] 则处理信号
else if ((sockfd == pipefd[0]) && (events[i].events & EPOLLIN))
{
//处理信号
}
}
}
return 0;
}
完整代码在这里