zoukankan      html  css  js  c++  java
  • 统一事件源epoll代码示例

    可以将信号注册进pipe管道的写端,通过对读端的监听,来实现统一事件源。

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/epoll.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #include <assert.h>
    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <pthread.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;
    }
    
    void addfd(int epollfd, int fd) {
            epoll_event event;
            event.data.fd = fd;
            event.events = EPOLLIN | EPOLLET;
            epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
            setnonblocking(fd);
    }
    
    void sig_handler(int sig) {
            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, '', 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) {
                    printf("usage: %s ip port
    ", basename(argv[0]));
                    return 1;
            }
            const char *ip = argv[1];
            int port = atoi(argv[2]);
    
            int ret = 0;
            sockaddr_in address;
            bzero(&address, sizeof(address));
            address.sin_family = AF_INET;
            inet_pton(AF_INET, ip, &address.sin_addr);
            address.sin_port = htons(port);
    
            int listenfd = socket(PF_INET, SOCK_STREAM, 0);
            assert(listenfd >= 0);
    
            ret = bind(listenfd, (sockaddr*)&address, sizeof(address));
            if (ret == -1) {
                    printf("errno is %d
    ", errno);
                    return 1;
            }
            ret = listen(listenfd, 5);
            assert(ret != -1);
    
            epoll_event events[MAX_EVENT_NUMBER];
            int epollfd = epoll_create(5);
            assert(epollfd != -1);
            addfd(epollfd, listenfd);
    
            ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd);
            assert(ret != -1);
            setnonblocking(pipefd[1]);
            addfd(epollfd, pipefd[0]);
    
            addsig(SIGHUP);
            addsig(SIGCHLD);
            addsig(SIGTERM);
            addsig(SIGINT);
            bool stop_server = false;
    
            while (!stop_server) {
                    int number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
                    if ((number < 0) && (errno != EINTR)) {
                            printf("epoll failure
    ");
                            break;
                    }
    
                    for (int i=0; i<number; i++) {
                            int sockfd = events[i].data.fd;
                            if (sockfd == listenfd) {
                                    printf("New connection is coming.
    ");
                                    sockaddr_in client_address;
                                    socklen_t client_addrlen = sizeof(client_address);
                                    int connfd = accept(listenfd, (sockaddr*)&client_address,
                                                    &client_addrlen);
                                    printf("New connection established.
    ");
                                    addfd(epollfd, connfd);
                            }
                            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 {
                                            for (int i=0; i<ret; ++i) {
                                                    switch(signals[i]) {
                                                            case SIGCHLD:
                                                            {
                                                                    printf("SIGCHLD CONTINUE
    ");
                                                                    continue;
                                                            }
                                                            case SIGHUP:
                                                            {
                                                                    printf("SIGHUP CONTINUE
    ");
                                                                    continue;
                                                            }
                                                            case SIGTERM:
                                                            {
                                                                    printf("SIGTERM END PROGRAM
    ");
                                                                    stop_server = true;
                                                                    break;
                                                            }
                                                            case SIGINT:
                                                            {
                                                                    printf("SIGINT END PROGRAM
    ");
                                                                    stop_server = true;
                                                                    break;
                                                            }
                                                    }
                                            }
                                    }
                            }
                            else {
                                    // handle connected fd, ignore
                            }
                    }
            }
    
            printf("close fds
    ");
            close(listenfd);
            close(pipefd[1]);
            close(pipefd[0]);
            return 0;
    
    }

    Makefile的文件内容:

    uniserver : uniserver.cpp
            g++ -o uniserver uniserver.cpp -lpthread

    编译出服务器程序之后,运行服务器:

    $ ./uniserver 127.0.0.1 12111 
    New connection is coming.
    New connection established.
    SIGTERM END PROGRAM
    close fds
    $ ./uniserver 127.0.0.1 12111 
    ^CSIGINT END PROGRAM
    close fds

    运行客户端:

    $ telnet 127.0.0.1 12111 
    Trying 127.0.0.1...
    Connected to localhost.localdomain (127.0.0.1).
    Escape character is '^]'.
    a
    ^C^]
    telnet> quit
    Connection closed.
    $ ps ux | grep uniserver
    work     20265  0.0  0.0  8192  828 pts/0    S+   23:22   0:00 ./uniserver 127.0.0.1 12111
    work     20806  0.0  0.0 51132  580 pts/1    S+   23:23   0:00 grep uniserver
    $ kill 20265

    可以看出,客户端的连接请求得到服务器端的响应;发出的内容"a"在服务器端没有处理和展现。

    使用向服务器发信号,得到处理;服务器端直接Ctrl+C也得到了处理。

    同时可以看出,信号是int类型,但是传输的时候,采用的是char*,并且只传输了一个字节就可以了;在接收端进行switch的时候,也只针对char数据的一个元素进行比对就可以了。 

  • 相关阅读:
    JNI在C 和 C++ 函数实现的不同
    JNI输出log信息
    Android.mk相关知识
    Android项目编译和使用C语言动态库(so库)
    Jmeter之JDBC请求(四)
    Jmeter之Badboy录制脚本及简化脚本http请求(三)
    Jmeter之录制脚本(二)
    Android自动化压力测试之Monkey Test 异常解读(五)
    Android自动化压力测试之Monkey Test Android常见的错误类型及黑白名单的使用方法(四)
    Android自动化压力测试之Monkey Test (三)
  • 原文地址:https://www.cnblogs.com/charlesblc/p/5554785.html
Copyright © 2011-2022 走看看