本文共 2750 字,大约阅读时间需要 9 分钟。
#include#include #include #include #include #include #include #include #include #include #include #include #define LISTEM_NUM 5#define MAX_EVENT_NUM 1024int setnonblocking(int fd);void add_epoll_fd(int epoll_fd,int fd);void sig_handler(int sigalno);void add_sig(int sigalno);static int pipe_fd[2];int main(int argc,char* argv[]){ if(argc!=3){ printf("usage:./%s [server ip] [server port]\n",basename(argv[1])); exit(EXIT_FAILURE); } int ser_fd,server_port; const char* server_ip; //创建套接字 if((ser_fd=socket(AF_INET,SOCK_STREAM,0))==-1){ perror("socket"); exit(EXIT_FAILURE); } //初始化服务端地址 struct sockaddr_in server_address; server_ip=argv[1]; server_port=atoi(argv[2]); bzero(&server_address,sizeof(server_address)); server_address.sin_family=AF_INET; server_address.sin_port=htons(server_port); if(inet_pton(AF_INET,server_ip,&server_address.sin_addr.s_addr)==-1){ perror("inet_pton"); exit(EXIT_FAILURE); } //绑定服务端地址 if(bind(ser_fd,(struct sockaddr*)&server_address,sizeof(server_address))==-1){ perror("bind"); exit(EXIT_FAILURE); } //开启监听 if(listen(ser_fd,LISTEM_NUM)==-1){ perror("bind"); exit(EXIT_FAILURE); } int epoll_fd; //创建epoll事件表句柄 if((epoll_fd=epoll_create(5))==-1){ perror("epoll_create"); exit(EXIT_FAILURE); } //将服务端套接字加入到事件表中 add_epoll_fd(epoll_fd,ser_fd); //创建管道 if(socketpair(PF_UNIX,SOCK_STREAM,0,pipe_fd)==-1){ perror("socketpair"); exit(EXIT_FAILURE); } /*sockpair函数创建的管道是全双工的,不区分读写端 此处我们假设pipe_fd[1]为写端,非阻塞 pipe_fd[0]为读端 */ setnonblocking(pipe_fd[1]); add_epoll_fd(epoll_fd,pipe_fd[0]); //为一些信号绑定信号处理函数 add_sig(SIGHUP); //终端接口检测到一个连接断开,发送此信号 add_sig(SIGCHLD);//子进程终止或停止时,子进程发送此信号 add_sig(SIGTERM);//接收到kill命令 add_sig(SIGINT); //用户按下中断键(Delete或Ctrl+C) int server_running=1; int epoll_wait_ret_value; struct epoll_event events[MAX_EVENT_NUM]; while(server_running) { bzero(events,sizeof(events)); epoll_wait_ret_value=epoll_wait(epoll_fd,events,MAX_EVENT_NUM,-1); //epoll_wait函数出错 if((epoll_wait_ret_value==-1)&&(errno!=EINTR)){ close(ser_fd); perror("epoll_wait"); exit(EXIT_FAILURE); } //遍历就绪的事件 for(int i=0;i
代码解析
- 创建一个无名管道,管道[0]端用来读取数据,[1]端用来发送数据。读写端都设置为非阻塞
- 当信号处理函数执行时,在处理函数中向[1]端发送信号编号
- 主函数使用epoll轮询,其中包括轮询管道[0],一旦有信息(信号编号)发来,处理信号
代码演示
- 使用客户端工具连接程序,打印客户端连接信息
- 使用kill命令给服务端程序发送一个编码为1的信号,可以看到服务端接收到这个信号
- 按下Ctrl+C触发SIGINT信号,程序终止(与预期一致)
转载地址:http://ltkki.baihongyu.com/