【Linux网络编程-6】IO复用

1.select模型

//selectServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <errno.h>
#include <vector>

int InitServer(const unsigned int port);

int main(int argc,char** argv)
{
    int listenfd=InitServer(atoi(argv[1]));
    if(listenfd==-1)
    {
        printf("InitServer failed..\n");
        return -1;
    }

    std::vector<int> clientfds;

    fd_set readfdset;
    FD_ZERO(&readfdset);
    FD_SET(listenfd,&readfdset);
    int maxfd;
    maxfd=listenfd;
    struct timeval sttime;
    sttime.tv_sec=30;
    while(true)
    {
        fd_set readfdsetTmp=readfdset;
        int infds=select(maxfd+1,&readfdsetTmp,NULL,NULL,NULL);
        if(infds<0)
        {   
            printf("select error..\n");
            perror("select failed: ");
            break;
        }
        else if(infds==0)
        {
            printf("timeout..\n");
            continue;
        }
        else
        {
            for(int eventfd=0;eventfd<=maxfd;eventfd++)
            {
                if(FD_ISSET(eventfd,&readfdsetTmp)<=0)
                    continue;
                if(eventfd==listenfd) 
                {
                    //发生listen事件,有client连接
                    struct sockaddr_in client_addr;
                    socklen_t client_addr_size=sizeof(client_addr);
                    int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,(socklen_t*)&client_addr_size);
                    
                    printf("client(%d) connectd..\n",clientfd);
                    FD_SET(clientfd,&readfdset);
                    //添加描述符,更新maxfd
                    if(maxfd<clientfd) 
                        maxfd=clientfd;
                    clientfds.push_back(clientfd);
                    continue;
                }
                else
                {
                    //有数据可读事件,或对端断开事件
                    char buf[1024];
                    memset(buf,0,sizeof(buf));
                    size_t isize = recv(eventfd,buf,sizeof(buf),0);	//clientfd是会变的,要传eventfd进recv和send
                    if(isize<0)
                    {
                        //断开连接
                        printf("client(%d) disconneted..\n",eventfd);
                        close(eventfd);	//关闭连接
                        for(auto iter=clientfds.begin();iter!=clientfds.end();iter++)
                        {
                            if(*iter==eventfd)
                                clientfd.erase(iter);
                        }
                        FD_CLR(eventfd,&readfdset);	//该bit位置0
                        if(eventfd==maxfd)	//只有当移除的eventfd是maxfd时,才需要更新maxfd
                        {
                            for(int i=maxfd;i>=0;i--)	//找到新的最大的还是1的eventfd
                            {
                                if(FD_ISSET(eventfd,&readfdset))
                                {
                                 	maxfd=eventfd;
                                    break;
                                }
                            }
                        }
                        continue;
                    }
					
                    //接收数据
                    printf("recv(%d):%s,size=%d\n",eventfd,buf,isize) ;
                    send(eventfd,buf,strlen(buf),0);

                }

            }
        }

    }
    return 0;
}

int InitServer(const unsigned int port)
{
    int sockfd=-1;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) return -1;

    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    server_addr.sin_port=htons(port);

    if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }
    
    if(listen(sockfd, 5) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }

    return sockfd;
}
//selectClient.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <netdb.h>


bool ConnectServer(int* sockfd, const char* ip, int port);

int main(int argc,char** argv)
{
    int serverfd=-1;
    if(ConnectServer(&serverfd,"127.0.0.1",atoi(argv[1]))==false)
    {
        printf("connect failed..\n");
        return -1;
    }
    printf("connected..\n");

    char buf[1024];
    while(true)
    {
        memset(buf,0,sizeof(buf));
        printf("enter input:\n");
        scanf("%s",buf);

        if(send(serverfd,buf,strlen(buf),0)==false)
        {
            printf("send error..\n");
            return -1;
        }
        printf("send:%s\n",buf);
        
        memset(buf,0,sizeof(buf));
        if(recv(serverfd,buf,sizeof(buf),0)==false)
        {
            printf("recv error..\n");
            return -1;
        }
        printf("recv:%s\n",buf);
    }

    return 0;
}

bool ConnectServer(int* sockfd, const char* ip, int port)
{
    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));
	server_addr.sin_family=AF_INET;

	server_addr.sin_addr.s_addr=inet_addr(ip);	
	server_addr.sin_port=htons(port);
	
    *sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(*sockfd==-1)
    {
        return false;
    }
 
	if(connect(*sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
        close(*sockfd);
        *sockfd=-1;
        return false;
    }

    return true;
}

2.poll模型

//pollServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <vector>
#include <time.h>
#include <poll.h>
#include <fcntl.h>

#define MAXNFDS 1024

int InitServer(const unsigned int port);

int main(int argc,char** argv)
{
    int listenfd=InitServer(atoi(argv[1]));
    printf("listenfd=%d\n",listenfd);
    if(listenfd==-1)
    {
        printf("InitServer failed..\n");
        return -1;
    }

    //初始化数组
    int maxfd;
    struct pollfd fds[MAXNFDS];
    for(int i=0;i<MAXNFDS;i++)
    {
        fds[i].fd=-1;
    }
    //添加listenfd到数组
    fds[listenfd].fd=listenfd;
    fds[listenfd].events=POLLIN;	//监听读数据事件
    fds[listenfd].revents=0;
    maxfd=listenfd;

    while(1)
    {
        int infds=poll(fds,maxfd+1,-1);
        if(infds<0)
        {   
            printf("poll error..\n");
            perror("poll failed: ");
            break;
        }
		//超时返回0
        if(infds==0)
        {
            printf("timeout..\n");
            continue;
        }

        //遍历数组
        for(int eventfd=0;eventfd<=maxfd;eventfd++)
        {
            if(fds[eventfd].fd==-1) //-1表示不监视描述符
                continue;
			
            /*
            if(!(fds[eventfd].revents&POLLIN))   //发生的不是POLLIN数据可读事件
                continue;
            fds[eventfd].revents=0; //revents置0
            */
            
            //下面是数据可读事件
            if((eventfd==listenfd) && (fds[eventfd].revents&POLLIN)) 
            {
	                fds[eventfd].revents=0;
                    struct sockaddr_in client_addr;
                    socklen_t client_addr_size=sizeof(client_addr);
                    int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,&client_addr_size);
                    if(clientfd<0)
                        printf("accept failed..\n");
                    printf("%ld client(%d) connectd..\n",time(0),clientfd);
                    //close client which is more than MAXNFDS
                    if(clientfd>MAXNFDS)
                    {
                        printf("clientfd(%d) > MAXNFDS(%d), close client..\n",clientfd,MAXNFDS);
                        close(clientfd);
                        continue;
                    }

                    //把clientfd添加监视
                    fds[clientfd].fd=clientfd;
                    fds[clientfd].events=POLLIN;
                    fds[clientfd].revents=0;
                    //更新maxfd
                    if(maxfd<clientfd) 
                        maxfd=clientfd;
                    printf("maxfd=%d\n",maxfd);
                    continue;
            }
            else if(fds[eventfd].revents&POLLIN)
            {
                fds[eventfd].revents=0;
                char buf[1024];
                memset(buf,0,sizeof(buf));
                size_t isize = recv(eventfd,buf,sizeof(buf),0);
                if(isize<=0)
                {
                    printf("%ld client(%d) disconneted..\n",time(0),eventfd);
                    close(eventfd);
                        
                    //client断开,将clientfd移除监视
                    fds[eventfd].fd=-1;
                    if(eventfd==maxfd)	//更新maxfd
                    {
                        for(int i=maxfd;i>0;i--)
                        {
                            if(fds[i].fd!=-1)
                                maxfd=i;
                                break;
                        }
                        printf("maxfd=%d\n",maxfd);
                    }
                    continue;
                }
                //printf("recv(%d):%s,size=%d\n",eventfd,buf,isize) ;
                
                send(eventfd,buf,strlen(buf),0);
            }
        }
    }
    return 0;
}

int InitServer(const unsigned int port)
{
    int sockfd=-1;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) return -1;

    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    server_addr.sin_port=htons(port);

    if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }
    
    if(listen(sockfd, 5) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }

    return sockfd;
}

3.epoll模型

//epollServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <vector>
#include <time.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define MAXEVENTS 100

int InitServer(const unsigned int port);

int main(int argc,char** argv)
{
    int listenfd=InitServer(atoi(argv[1]));
    printf("listenfd=%d\n",listenfd);
    if(listenfd==-1)
    {
        printf("InitServer failed..\n");
        return -1;
    }

    //创建epoll句柄
    int epollfd=epoll_create(1);
    if(epollfd<0)   printf("epoll_create failed..\n");

    //epoll_event封装listenfd和监视类型为有数据可读(EPOLLIN)
    struct epoll_event ev;
    ev.data.fd=listenfd;
    ev.events=EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&ev);	//添加到epollfd

    while(true)
    {
        struct epoll_event events[MAXEVENTS];	//epoll_wait返回时保存发生的事件
        int infds=epoll_wait(epollfd,events,MAXEVENTS,-1);
        if(infds<0) 
        {
            printf("epoll_wait failed..\n");
            break;
        }
        if(infds==0)
        {
            printf("timeout..\n");
            break;
        }
        
        //发生的事件再events中从index=0依次保存
        for(int i=0;i<infds;i++) 
        {
            //listenfd上有数据可读事件发生
            if((events[i].data.fd==listenfd) && (events[i].events&EPOLLIN))
            {
                struct sockaddr_in client_addr;
                socklen_t client_addr_size=sizeof(client_addr);
                int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,&client_addr_size);
                if(clientfd<0)
                {
                    printf("accept failed..\n");
                    continue;
                }

                //连接上的客户端添加进监视
                memset(&ev,0,sizeof(struct epoll_event));	//清空ev
                
                ev.data.fd=clientfd;
                ev.events=EPOLLIN;
                epoll_ctl(epollfd,EPOLL_CTL_ADD,clientfd,&ev);
                printf("%ld client(%d) connectd..\n",time(0),clientfd);
                continue;
            }
            else if(events[i].events&EPOLLIN)	//有数据可读事件
            {
                char buf[1024];
                memset(buf,0,sizeof(buf));
                size_t isize = recv(events[i].data.fd,buf,sizeof(buf),0);

                if(isize<=0)
                {
                    //把客户端fd从监视中删除
                    memset(&ev,0,sizeof(struct epoll_event));
                    ev.data.fd=events[i].data.fd;
                    ev.events=EPOLLIN;
                    epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,&ev);

                    close(events[i].data.fd);
                    printf("%ld client(%d) disconneted..\n",time(0),events[i].data.fd);
                    continue;
                }
 
                printf("client(%d)recv msg:%s,size=%d\n",events[i].data.fd,buf,isize);

                //send(events[i].data.fd,buf,strlen(buf),0);
                //判断sockfd是否可写
			   fd_set tmpfd;
			   FD_ZERO(tmpfd);
			   FD_SET(events[i].data.fd,&tmpfd);
			   if(select(events[i].data.fd+1,0,&tmpfd,0,0)<0)
			   {
			       printf("没有可写数据的fd\n");
			       return -1;
			   }
			   if(write(events[i].data.fd,buf,strlen(buf))<0)
			   {
			       printf("write failed..\n");
			       close(events[i].data.fd);
			       return -1;
			   }
                
            }
       }
    }
    return 0;
}

int InitServer(const unsigned int port)
{
    int sockfd=-1;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) return -1;

    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    server_addr.sin_port=htons(port);

    if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }
    
    if(listen(sockfd, 5) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }

    return sockfd;
}
posted @ 2024-07-15 17:51  徘徊彼岸花  阅读(1)  评论(0编辑  收藏  举报