linux下的epoll函数

epoll是TCP/IP网络编程的IO服用方法之中一种优于select的函数,相比select,它有两个优点:
1.无需编写以监视状态变化为目的的针对所有文件描述符的循环语句。
2.调用对应于select函数的epoll_wait函数时无需每次传递监视对象信息。
下面介绍epoll服务器端实现中需要的三个函数,希望各位结合epoll函数的优点理解这些函数的功能。
epoll_create:创建保存epoll文件描述符的空间。
epoll_ctl:向空间注册并注销文件描述符。
epoll_wait:等待文件描述符发生变化。
此外还需要一种结构体:epoll_event将发生变化的文件描述符单独集中到一起。
struct epoll_event{
__unint32_t events;
epoll_data_t data;
}
用法:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/epoll.h>

void error_handling(char *message);

#define BUFF_SIZE 100
#define EPOLL_SIZE 30

int main(int argc, char *argv[])
{
    int sock_server;
    int sock_client;

    struct sockaddr_in addr_server;
    struct sockaddr_in addr_client;
    socklen_t size_addr_client;

    char buff[BUFF_SIZE];
    int str_len, i;

    int epfd, count_event;
    struct epoll_event *ep_events;
    struct epoll_event event;


    if(argc!=2){ //命令行中启动服务程序仅限一个参数:端口号
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    //调用socket函数创建套接字
    sock_server = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == sock_server){
        error_handling("socket() error.");
    }

    memset(&addr_server, 0, sizeof(addr_server));
    addr_server.sin_family = AF_INET;
    addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_server.sin_port = htons(atoi(argv[1]));

    //调用bind函数分配IP地址和端口号
    if( -1 == bind( sock_server, (struct sockaddr*)&addr_server, 
                sizeof(addr_server)) ){
        error_handling("bind() error");
    }

    //监听端口的连接请求,连接请求等待队列size为5
    if( -1 == listen(sock_server, 5) ){
        error_handling("listen() error");
    }

    //epoll
    epfd = epoll_create(EPOLL_SIZE);
    //epfd = epoll_create(0); //epoll_wait() Error
    ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event)*EPOLL_SIZE);

    event.events = EPOLLIN;//监视需用读取数据事件
    event.data.fd=sock_server;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sock_server, &event);
    //
    while(1){
        count_event = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
        if(count_event == -1){
            puts("epoll_wait() Error");
            break;
        }

        for(i=0; i<count_event; i++){
            if(ep_events[i].data.fd == sock_server){
                //接受连接请求
                size_addr_client = sizeof(addr_client);
                sock_client = accept( sock_server, (struct sockaddr*)&addr_client, &size_addr_client);
                event.events = EPOLLIN;
                event.data.fd = sock_client;
                epoll_ctl(epfd, EPOLL_CTL_ADD, sock_client, &event);
                printf("Connected client : %d\n", sock_client);
            }else{
                str_len = read(ep_events[i].data.fd, buff, BUFF_SIZE);
                if(str_len){//echo to client
                    buff[str_len] = 0;
                    printf("Message from client %d: %s", i, buff);
                    write(ep_events[i].data.fd, buff, str_len);//echo!
                }else{ //close connection
                    epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
                    close(ep_events[i].data.fd);
                    printf("Disconnected client %d!\n", ep_events[i].data.fd);
                }
            }//end of if()
        }//end of while
    }//end of for

    //断开连接,关闭套接字
    close(sock_server);
    close(epfd);//

    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(EXIT_FAILURE);
}

猜你喜欢

转载自blog.csdn.net/qq_36946274/article/details/80784888