I/O多路转接(三)——epoll函数

来源:互联网 发布:中企动力域名到期 编辑:程序博客网 时间:2024/05/16 12:52

I/O多路转接(三)——epoll函数

第三篇介绍epoll函数。
介绍先略过,还在整理当中,先贴代码。

使用epoll LT与ET模式的网路服务器

LT
这是一个简单的服务器,三次握手后只完成一次读写就关闭连接。通过浏览器发送一个HTTP请求,服务器传回HELLO EPOLL消息。
server.c

#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<sys/stat.h>#include<stdlib.h>#include<string.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/epoll.h>const char *msg = "HTTP/1.1 200 OK\r\n\r\n<html><h1>Hello epoll!</h1></html>";int startup(char*ip,int port){    int sock = socket(AF_INET,SOCK_STREAM,0);    if(sock < 0){        perror("socket");        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){        printf("Usage:%s [ip] [port]\n",argv[0]);        return 1;    }    int listen_sock = startup(argv[1],atoi(argv[2]));    printf("listen_sock has been created,the value is %d\n",listen_sock);    //监听套接字创建完成.    int epfd = epoll_create(256);//创建epoll模型,返回一个epoll模型句柄。    if(epfd < 0){        perror("epoll_create");        return 5;    }    struct epoll_event ev;    ev.events = EPOLLIN;    ev.data.fd = listen_sock;    epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev);//将listen_sock添加到rb_tree;    int nums = -1;    int timeout = 1000;    struct epoll_event revs[64];//epoll事件集    int size = 64;    while(1){        nums = epoll_wait(epfd,revs,size,-1);        switch(nums){            case 0:                printf("timeout\n");                break;            case -1:                perror("epoll_wait");                break;            default:                {                    //已经有事件就绪。                    int i= 0;                    for(;i < nums;i++){                        int fd = revs[i].data.fd;                        if(fd==listen_sock&&revs[i].events&EPOLLIN{                        //listen_sock读事件已经就绪。                            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");                                continue;                            }                                printf("get a client!ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));                                //将CLIENT的socket添加到epoll中                                ev.events = EPOLLIN;                                ev.data.fd = new_sock;                                epoll_ctl(epfd,EPOLL_CTL_ADD,new_sock,&ev);                        }else if(fd!= listen_sock){//其他关心描述符状态改变。                            if(revs[i].events&EPOLLIN){                                char buf[4096];                                ssize_t s = read(fd,buf,sizeof(buf)-1);                                if(s >0){                                    buf[s]= 0;                                    printf("client say# %s\n",buf);                                    ev.events = EPOLLOUT;//读后关心这个fd的写事件。                                    ev.data.fd = fd;                                    epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev);                                }else if(s==0){                                    printf("client is quit!\n");                                    close(fd);                                    epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);                                }else{                                    perror("read");                                    close(fd);                                    epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);                                }                            }else if(revs[i].events&EPOLLOUT){                                write(fd,msg,strlen(msg));                                close(fd);                                epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);                            }                        }                    }                 }                break;         }    }

使用epoll ET模式的网路服务器

#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<sys/stat.h>#include<stdlib.h>#include<string.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/epoll.h>#include<errno.h>#include<fcntl.h>const char *msg = "HTTP/1.1 200 OK\r\n\r\n<html><h1>Hello epoll!</h1></html>";struct epoll_event ev;#define SIZE 64typedef struct fd_buff{    int fd;    char buf[SIZE];    int size;}fdbuff,*fdbuff_p;void* alloc_buff(int fd){    fdbuff_p tmp =(fdbuff_p)malloc(sizeof(fdbuff));    if(!tmp){        perror("malloc");        return NULL;    }    tmp->fd = fd;    tmp->size = SIZE;    return tmp;}int startup(char*ip,int port){    int sock = socket(AF_INET,SOCK_STREAM,0);    if(sock < 0){        perror("socket");        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;} void set_nonblock(int fd)//设置套接字为非阻塞。{    int fl = fcntl(fd, F_GETFL);//拿到当前套接字状态保存到fl    fcntl(fd,F_SETFL,fl|O_NONBLOCK);//设置为非阻塞态}int myread(int fd, char buf[],int size){    ssize_t len = 0;    ssize_t total = 0;    int count = 0;    while((len = read(fd,buf+total,100))> 0){        count++;        total += len;        printf("read %d!msg:%s total = %d\n",count,buf,total);    }    if(len < 0||errno== EAGAIN)        printf("read done! total = %d\n",total);    else if(len==0)        return 0;    else        return -1;    return total;}int mywrite(int fd, char buf[],int size){    ssize_t len = 0;    ssize_t total = 0;    int count = 0;    while(1){        len = write(fd,buf+total,strlen(buf+total));        if(len > 0)            total += len;        if(len < 0||errno== EAGAIN){                printf("write done! total = %d\n",total);                break;        }    }    return total;}int myaccept(int listen_sock,int epfd){    struct sockaddr_in client;    socklen_t len = sizeof(client);    int new_sock = 0;    int count = 0;    while(( new_sock = accept(listen_sock,(struct sockaddr*)&client,&len))>0){        count++;        printf("get a client!ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));        //将CLIENT的socket添加到epoll中        ev.events = EPOLLIN|EPOLLET;        set_nonblock(new_sock);        ev.data.ptr = alloc_buff(new_sock);        epoll_ctl(epfd,EPOLL_CTL_ADD,new_sock,&ev);    }    if(new_sock < 0&&errno==EAGAIN){        printf("server has accept all client,count= %d\n",count);    }}void del_buff(fdbuff_p p){    if(p!=NULL)        free(p);}int main(int argc,char *argv[]){    if(argc!= 3){        printf("Usage:%s [ip] [port]\n",argv[0]);        return 1;    }    int listen_sock = startup(argv[1],atoi(argv[2]));    set_nonblock(listen_sock);    printf("listen_sock has been created,the value is %d\n",listen_sock);    //监听套接字创建完成.    int epfd = epoll_create(256);//创建epoll模型,返回一个epoll模型句柄。    if(epfd < 0){        perror("epoll_create");        return 5;    }    ev.events = EPOLLIN|EPOLLET;    ev.data.ptr =alloc_buff(listen_sock);    epoll_ctl(epfd,EPOLL_CTL_ADD,listen_sock,&ev);//将listen_sock添加到rb_tree;    int nums = -1;    int timeout = 1000;    struct epoll_event revs[64];//epoll事件集    int size = 64;    while(1){        nums = epoll_wait(epfd,revs,size,-1);        switch(nums){            case 0:                printf("timeout\n");                break;            case -1:                perror("epoll_wait");                break;            default:                {                    //已经有事件就绪。                    int i= 0;                    for(;i < nums;i++){                        fdbuff_p fp =(fdbuff_p)revs[i].data.ptr;                        if(fp->fd == listen_sock&&revs[i].events&EPOLLIN ){//listen_sock读事件已经就绪。                            myaccept(listen_sock, epfd);                        }else if(fp->fd!= listen_sock){//其他关心描述符状态改变。                            if(revs[i].events&EPOLLIN){                                ssize_t s = myread(fp->fd,fp->buf,fp->size);                                if(s >0){                                    fp->buf[s]=0;                                    printf("client say# %s\n",fp->buf);                                    ev.events = EPOLLOUT|EPOLLET;//读后关心这个fd的写事件。                                    ev.data.ptr = fp;                                    epoll_ctl(epfd,EPOLL_CTL_MOD,fp->fd,&ev);                                }else if(s==0){                                    printf("client is quit!\n");                                    close(fp->fd);                                    epoll_ctl(epfd,EPOLL_CTL_DEL,fp->fd,NULL);                                    del_buff(fp);                                }else{                                    perror("read");                                    close(fp->fd);                                    epoll_ctl(epfd,EPOLL_CTL_DEL,fp->fd,NULL);                                    del_buff(fp);                                }                            }else if(revs[i].events&EPOLLOUT){                                mywrite(fp->fd,fp->buf,fp->size);                                close(fp->fd);                                epoll_ctl(epfd,EPOLL_CTL_DEL,fp->fd,NULL);                                //del_buff(fp);                            }                        }                    }                 }                break;         }    }    return 0;}
原创粉丝点击