【网络编程(四)】IO多路复用(2)

上一节讲了select , poll。

但是现代的linux系统对于多路富用采用的更多为epoll函数。

epoll比前两个函数更加好用,下面给出具体用法。

void server6(){
    const uint16_t listened_port=9000;
    const char* localhost="127.0.0.1";
    const int listening_queue_length=1024;
    const int buffersize=1024;

    int listen_fd=socket(AF_INET,SOCK_STREAM,0);
    sockaddr_in server_addr,client_addr;
    socklen_t len;

    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    in_addr temp;
    inet_pton(AF_INET,localhost,&server_addr.sin_addr);
    server_addr.sin_port=htons(listened_port);

    bind(listen_fd,(const sockaddr*)&server_addr,sizeof(server_addr));
    listen(listen_fd,listening_queue_length);

    char buf[buffersize];

    epoll_event ev,events[20];
    int epoll_fd=epoll_create(1024);
    ev.data.fd=listen_fd;
    ev.events=EPOLLIN|EPOLLET;

    if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_fd,&ev)<0){
        cerr<<"error in epoll_ctl "<<endl;
        exit(1);
    }

    int nfds;
    while(1){
        nfds=epoll_wait(epoll_fd,events,20,-1);
        cout<<"event number ->"<<nfds<<endl;
        for(int i=0;i<nfds;++i){
            if(events[i].data.fd==listen_fd){
                int connect_fd=accept(listen_fd,(sockaddr*)&client_addr,&len);
                if(connect_fd<0){
                    cerr<<"error in connect..."<<endl;
                    continue;
                }
                cout<<"get connection..."<<endl;
                printf("client info :%s\n",inet_ntoa(client_addr.sin_addr));
                ev.data.fd=connect_fd;
                ev.events=EPOLLIN|EPOLLET;
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, connect_fd, &ev);
            }
            else if(events[i].events&EPOLLOUT){
                cout<<"fd is writeable.("<<events[i].data.fd<<")"<<endl;
                int newfd=events[i].data.fd;
                if(newfd<0){
                    cout<<"new fd<0"<<endl;
                    continue;
                }
                const char* hello="hi client";
                int f=write(events[i].data.fd,hello,strlen(hello));
                if(f<0){
                    cerr<<"write error.."<<endl;
                }
                cout<<"write message ok.."<<endl;
                ev.data.fd=events[i].data.fd;
                ev.events=EPOLLOUT|EPOLLET;
                epoll_ctl(epoll_fd,EPOLL_CTL_DEL,events[i].data.fd,&ev);
            }
            else if(events[i].events&EPOLLIN){
                cout<<"fd is readable.("<<events[i].data.fd<<")"<<endl;
                int new_fd=events[i].data.fd;
                if(new_fd<0){
                    cout<<"new-fd<0"<<endl;
                    continue;
                }
                int n;
                if((n=read(new_fd,buf,buffersize))<0){
                    if(errno==ECONNRESET){
                        close(new_fd);
                        events[i].data.fd=-1;
                        cerr<<"ECONNRESET.."<<endl;
                    }
                    else{
                        cerr<<"read buffer error"<<endl;
                    }

                }
                else if(n==0){
                    close(new_fd);
                    events[i].data.fd=-1;
                    cout<<"read 0 bytes"<<endl;
                }
                cout<<"get message:"<<buf<<endl;
                ev.data.fd=events[i].data.fd;
                ev.events=EPOLLOUT|EPOLLET;
                epoll_ctl(epoll_fd,EPOLL_CTL_MOD,new_fd,&ev);
            }
        }
    }




}

这里面epoll_ctl可以加入/修改/删除一个监听事件。epoll_create可以创建一组监听对象。逻辑思想和poll和select倒是很像。

发布了91 篇原创文章 · 获赞 22 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览