I/O多路转接技术

select(服务器端)

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

int main(){
    //创建socket
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(9999);
    saddr.sin_addr.s_addr=INADDR_ANY;

    //绑定
    bind(lfd,(struct sockaddr*)&saddr, sizeof(saddr));

    //监听
    listen(lfd,8);

    //创建一个fd_set的集合,存放的是需要检测的文件描述符
    fd_set rdset,tmp;
    FD_ZERO(&rdset);
    FD_SET(lfd,&rdset);
    int maxfd=lfd;

    while(1){
         
         tmp=rdset;

        //调用select系统函数,让内核帮检测哪些文件描述符有数据
        int ret=select(maxfd+1,&tmp,NULL,NULL,NULL);
        if(ret==-1){
            perror("select");
            exit(-1);
        }
        else if(ret==0){
            continue;
        }
        else if(ret>0){
            //说明检测到了有文件描述符的对应的缓冲区的数据发生了改变
            if(FD_ISSET(lfd,&tmp)){
                //表示有新的客户端连接进来了
                struct sockaddr_in caddr;
                socklen_t len=sizeof(caddr);
                int cfd=accept(lfd,(struct sockaddr*)&caddr,&len);

                //将新的文件描述符加入到集合中
                FD_SET(cfd,&rdset);
                
                //更新最大的文件描述符
                maxfd=maxfd>cfd?maxfd:cfd;
            }
            //监听描述符肯定在最前面
            for(int i=lfd+1;i<=maxfd;i++){
                if(FD_ISSET(i,&tmp)){
                    //说明这个文件描述符对应的客户端发来了数据
                    char buf[1025]={0};
                    int len=read(i,buf,sizeof(buf));
                    if(len==-1){
                        perror("read");
                        exit(-1);
                    }
                    else if(len==0){
                        printf("client closed\n");
                        close(i);
                        FD_CLR(i,&rdset);
                    }
                    else if(len>0){
                        printf("read buf= %s\n",buf);
                        write(i,buf,strlen(buf)+1);
                    }
                }
            }
        }

    }
    close(lfd);
    return 0;
}

poll(服务器端)

#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<poll.h>

int main(){
    //创建socket
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(9999);
    saddr.sin_addr.s_addr=INADDR_ANY;

    //绑定
    bind(lfd,(struct sockaddr*)&saddr, sizeof(saddr));

    //监听
    listen(lfd,8);

    //初始化检测的文件描述符数组
    struct pollfd fds[1024];
    for(int i=0;i<1024;i++){
        fds[i].fd=-1;
        fds->events=POLLIN;
    }
    fds[0].fd=lfd;

    int nfds=0;

    while(1){

        //调用poll系统函数,让内核帮检测哪些文件描述符有数据
        int ret=poll(fds,nfds+1,-1);
        if(ret==-1){
            perror("poll");
            exit(-1);
        }
        else if(ret==0){
            continue;
        }
        else if(ret>0){
            //说明检测到了有文件描述符的对应的缓冲区的数据发生了改变
            if(fds[0].revents & POLLIN ){
                //表示有新的客户端连接进来了
                struct sockaddr_in caddr;
                socklen_t len=sizeof(caddr);
                int cfd=accept(lfd,(struct sockaddr*)&caddr,&len);

                //将新的文件描述符加入到集合中
                for(int i=1;i<1024;i++){
                    if(fds[i].fd==-1){
                        fds[i].fd=cfd;
                        fds[i].events=POLLIN;
                        //更新最大的文件描述符
                        nfds=nfds>i?nfds:i;
                        break;
                    }
                }
                
            }
            //监听描述符肯定在最前面
            for(int i=1;i<=nfds;i++){
                if(fds[i].revents&POLLIN){
                    //说明这个文件描述符对应的客户端发来了数据
                    char buf[1025]={0};
                    int len=read(fds[i].fd,buf,sizeof(buf));
                    if(len==-1){
                        perror("read");
                        exit(-1);
                    }
                    else if(len==0){
                        printf("client closed\n");
                        close(fds[i].fd);
                        fds[i].fd=-1;
                    }
                    else if(len>0){
                        printf("read buf= %s\n",buf);
                        write(fds[i].fd,buf,strlen(buf)+1);
                    }
                }
            }
        }

    }
    close(lfd);
    return 0;
}

Epoll(服务器端)

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

int main(){
    //创建socket
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(9999);
    saddr.sin_addr.s_addr=INADDR_ANY;

    //绑定
    bind(lfd,(struct sockaddr*)&saddr, sizeof(saddr));

    //监听
    listen(lfd,8);

    //调用epoll_create在内核中创建一个epoll实例
    int epfd=epoll_create(100);
    //将监听的文件描述符相关的检测信息添加到epoll实例中
    struct epoll_event epev;
    epev.events=EPOLLIN;
    epev.data.fd=lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    struct epoll_event epevs[1024];
    while(1){

        int ret=epoll_wait(epfd,epevs,1024,-1);
        if(ret==-1){
            perror("epoll_wait");
            exit(-1);
        }

        printf("ret=%d\n",ret);

        for(int i=0;i<ret;i++){
            int curfd=epevs[i].data.fd;
            if(curfd==lfd){
                //监听的文件描述符有数据到达,有客户端连接
                 struct sockaddr_in caddr;
                socklen_t len=sizeof(caddr);
                int cfd=accept(lfd,(struct sockaddr*)&caddr,&len);

                epev.events=EPOLLIN;
                epev.data.fd=cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);
            }
            else{
                if(epevs[i].events&EPOLLOUT){
                    continue;
                }
                //有数据到达,需要通信
                char buf[1025]={0};
                int len=read(curfd,buf,sizeof(buf));
                if(len==-1){
                    perror("read");
                    exit(-1);
                }
                else if(len==0){
                    printf("client closed\n");
                    epoll_ctl(epfd,EPOLL_CTL_DEL,curfd,NULL);
                    close(curfd);
                }
                else if(len>0){
                    printf("read buf= %s\n",buf);
                    write(curfd,buf,strlen(buf)+1);
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}

Epoll_LT

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

int main(){

    //创建socket
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(9999);
    saddr.sin_addr.s_addr=INADDR_ANY;

    //绑定
    bind(lfd,(struct sockaddr*)&saddr, sizeof(saddr));

    //监听
    listen(lfd,8);

    

    //调用epoll_create在内核中创建一个epoll实例
    int epfd=epoll_create(100);
    //将监听的文件描述符相关的检测信息添加到epoll实例中
    struct epoll_event epev;
    epev.events=EPOLLIN;
    epev.data.fd=lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    struct epoll_event epevs[1024];
    while(1){

        int ret=epoll_wait(epfd,epevs,1024,-1);
        if(ret==-1){
            perror("epoll_wait");
            exit(-1);
        }

        printf("ret=%d\n",ret);

        for(int i=0;i<ret;i++){
            int curfd=epevs[i].data.fd;
            if(curfd==lfd){
                //监听的文件描述符有数据到达,有客户端连接
                 struct sockaddr_in caddr;
                socklen_t len=sizeof(caddr);
                int cfd=accept(lfd,(struct sockaddr*)&caddr,&len);

                epev.events=EPOLLIN;
                epev.data.fd=cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);
            }
            else{
                if(epevs[i].events&EPOLLOUT){
                    continue;
                }
                //有数据到达,需要通信
                char buf[5]={0};
                int len=read(curfd,buf,sizeof(buf));
                if(len==-1){
                    perror("read");
                    exit(-1);
                }
                else if(len==0){
                    printf("client closed\n");
                    epoll_ctl(epfd,EPOLL_CTL_DEL,curfd,NULL);
                    close(curfd);
                }
                else if(len>0){
                    printf("read buf= %s\n",buf);
                    write(curfd,buf,strlen(buf)+1);
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}

Epoll_ET

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

int main(){

    //创建socket
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(9999);
    saddr.sin_addr.s_addr=INADDR_ANY;

    //绑定
    bind(lfd,(struct sockaddr*)&saddr, sizeof(saddr));

    //监听
    listen(lfd,8);

    

    //调用epoll_create在内核中创建一个epoll实例
    int epfd=epoll_create(100);
    //将监听的文件描述符相关的检测信息添加到epoll实例中
    struct epoll_event epev;
    epev.events=EPOLLIN;
    epev.data.fd=lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    struct epoll_event epevs[1024];
    while(1){

        int ret=epoll_wait(epfd,epevs,1024,-1);
        if(ret==-1){
            perror("epoll_wait");
            exit(-1);
        }

        printf("ret=%d\n",ret);

        for(int i=0;i<ret;i++){
            int curfd=epevs[i].data.fd;
            if(curfd==lfd){
                //监听的文件描述符有数据到达,有客户端连接
                 struct sockaddr_in caddr;
                socklen_t len=sizeof(caddr);
                int cfd=accept(lfd,(struct sockaddr*)&caddr,&len);

                //设置cfd属性非阻塞
                int flag=fcntl(cfd,F_GETFL);
                flag |= O_NONBLOCK;
                fcntl(cfd,F_SETFL,flag);

                epev.events=EPOLLIN | EPOLLET;      //设置边缘触发
                epev.data.fd=cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);
            }
            else{
                
                //循环读取出所有数据
                char buf[5]={0};
                int len=0;
                while((len=read(curfd,buf, sizeof(buf)))>0){
                    //打印数据
                    printf("recv data : %s\n",buf);
                    write(curfd,buf,len);
                }
                if(len==0){
                    printf("client closed...\n");
                }
                else if(len==-1){
                    if(errno ==EAGAIN){
                        printf("data over....");
                    }
                    else{
                        perror("read");
                        exit(-1);
                    }
                    
                }
                
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值