eoll服务器

来源:互联网 发布:成都犀牛软件培训班 编辑:程序博客网 时间:2024/06/03 20:34

epoll实现(ET)

#include <stdio.h>#include <string.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/types.h>#include <stdlib.h>#include <sys/epoll.h>#include <fcntl.h>#include <errno.h>#include <assert.h>#include <pthread.h>#define MAX_READY_EVENTS 64//将文件描述符设置为非阻塞的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;}//将文件描述符fd上的EPOLLIN注册到epollfd指示的epoll内核事件表中,参数enable_et指定是否对fd启用ET模式void addfd(int epollfd, int fd, int enable_et){    struct epoll_event event;    event.data.fd = fd;    event.events = EPOLLIN;    if(enable_et)    {        event.events |= EPOLLET;    }    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);    setnonblocking(fd);}static void usage(const char* proc){    printf("Usage %s: [local_ip] [local_port]\n", proc);}int startup(const char* _ip, int _port){    int sock = socket(AF_INET, SOCK_STREAM, 0);    if(sock < 0)    {        perror("sock");        return 2;    }    int opt = 1;    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    struct sockaddr_in local;    local.sin_family = AF_INET;    local.sin_port = htons(_port);    local.sin_addr.s_addr = inet_addr(_ip);    if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)    {        perror("bind");        return 3;    }    if(listen(sock, 10) < 0)    {        perror("listen");        return 4;    }    return sock;}int main(int argc, char* argv[]){    if(argc != 3)    {        usage(argv[0]);        return 1;    }    int listen_sock = startup(argv[1], atoi(argv[2]));    int epfd = epoll_create(256);    if(epfd < 0)    {        perror("epoll_create");        return 5;    }    struct epoll_event ev;    ev.events = EPOLLIN;    ev.data.fd = listen_sock;    if(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) < 0)    {        perror("epoll_ctl");        return 6;    }    int timeout = 1000;    int nums = -1;    struct epoll_event revs[MAX_READY_EVENTS];    while(1)    {        switch(nums = epoll_wait(epfd, revs, MAX_READY_EVENTS, /*timeout*/-1))        {            case 0:                {                    printf("timeout...\n");                }                break;            case -1:                {                    perror("epolly_wait");                    return 7;                }                break;            default:                {                    int i = 0;                    for(; i < nums; i++)                    {                        int fd = revs[i].data.fd;                        if((fd == listen_sock) && (revs[i].events == EPOLLIN))                        {                            struct sockaddr_in client;                            socklen_t len = sizeof(client);                            int new_sock = accept(listen_sock, (struct sockaddr*)&client, &len);                            if(new_sock < 0)                            {                                perror("accept");                                return 8;                            }                            printf("get new client: [%s:%d]\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));                            struct epoll_event ev1;                            ev1.events = EPOLLIN;                            ev1.data.fd = new_sock;                            if(epoll_ctl(epfd, EPOLL_CTL_ADD, new_sock, &ev1) < 0)                            {                                perror("epoll_ctl");                                return 9;                            }                            addfd(epfd, new_sock, 1);//开启ET模式                        }// listen_sock can read                        else if((fd != listen_sock) && (revs[i].events & EPOLLIN))                        {                            //ET模式下下面代码不会重复触发,所以我们循环读取数据                            while(1)                            {                                char *buf[1024];                                int s = read(fd, buf, sizeof(buf)-1);                                if(s < 0)                                {                                    if((errno == EAGAIN) || (errno == EWOULDBLOCK))                                    {                                        break;                                    }                                    close(fd);                                    break;                                }                                else if(s == 0)                                {                                    printf("client quit...\n");                                    close(fd);                                }                                else                                {                                    buf[s] = 0;                                    printf("client ####:%s", buf);                                }                            }                        }//other events can read                        else if((fd != listen_sock) && (revs[i].events & EPOLLOUT))                        {                            char* msg = "";                            write(fd, msg, strlen(msg));                            close(fd);                            epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);                        }//events can write                    }//for                }//default                break;        }    }    return 0;}