linux编程---IO复用---select

来源:互联网 发布:多处理器编程的艺术 编辑:程序博客网 时间:2024/05/22 05:08

与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,

也不必维护这些进程/线程,从而大大减小了系统的开销。

/* According to POSIX.1-2001 */
       #include <sys/select.h>

       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>


       int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);



//将一个给定的文件描述符从集合中删除
       void FD_CLR(int fd, fd_set *set);

// 检查集合中指定的文件描述符是否可以读写 
       int  FD_ISSET(int fd, fd_set *set);

//将一个给定的文件描述符加入集合之中
       void FD_SET(int fd, fd_set *set);

//清空集合
       void FD_ZERO(fd_set *set);

实例如下

用select实现多客户接入服务器

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/time.h>
#include<sys/types.h>

#define MAXBUF 512
#define BACKLGO 10


int conn_amount;
int fd_cli[BACKLGO];

void showclient()  
{  
    int i;  
    printf("client amount: %d\n", conn_amount);  
    for (i = 0; i < BACKLGO; i++) {  
        printf("[%d]:clifd[%d]\t", i, fd_cli[i]);  
    }  
    printf("\n\n");  
}

int main(int argc,char* argv[])
{

    
    int serverfd,clifd,i;
    socklen_t len;
    struct sockaddr_in serveraddr,cliaddr;
    unsigned int serverport,lisnum;
    char buf[MAXBUF+1];
    fd_set rfds;
    struct timeval tv;
    int ret,maxfd = -1;
    
    serverport = 4332;
    lisnum = 5;
    
    socklen_t clilen = sizeof(struct sockaddr);
    if((serverfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        perror("socket");
        exit(-1);
    }
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(serverport);
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    if(bind(serverfd,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr)) < 0)
    {
        perror("bind");
        exit(-1);
    }
    
    if(listen(serverfd,lisnum)  < 0)
    {
        perror("listen");
        exit(-1);
    }
    for(i = 0;i<BACKLGO;i++)
        fd_cli[i] = 0;
    
    maxfd = serverfd;
    
    while(1)
    {
        
        FD_ZERO(&rfds);
        FD_SET(serverfd,&rfds);
        FD_SET(0,&rfds);
    
        tv.tv_sec = 30;
        tv.tv_usec = 0;
        
        for(i = 0;i<BACKLGO;i++)
        {
            if(fd_cli[i] != 0)
            {
                FD_SET(fd_cli[i],&rfds);
            }
        }
    
        
        ret = select(maxfd + 1,&rfds,NULL,NULL,&tv);
        if(ret == -1)
        {
            perror("select");
            exit(-1);
        }                
        else if(ret == 0)
        {
            continue;
        }
    else {
        for(i = 0; i< conn_amount;i++)
        {
            if(FD_ISSET(fd_cli[i],&rfds))
            {
                ret = recv(fd_cli[i],buf,sizeof(buf),0);
                char str[] = "hello client";
                send(fd_cli[i],str,sizeof(str)+1,0);
                
                if(ret <= 0)
                {
                    printf("client fd[%d] close\n",fd_cli[i]);
                    close(fd_cli[i]);
                    FD_CLR(fd_cli[i],&rfds);
                    fd_cli[i] = 0;
                }
                else
                {
                    if(ret < MAXBUF)
                        memset(&buf[ret],'\0',1);
                        printf("client fd [%d] send : [%s]\n",fd_cli[i],buf);
                }
            }
        }
        if(FD_ISSET(serverfd,&rfds))
        {
            clifd = accept(serverfd,(struct sockaddr*)&cliaddr,&clilen);
            if(clifd <= 0)
            {
                perror("accept");
                continue;
            }
            if(conn_amount < BACKLGO)
            {
                fd_cli[conn_amount++] = clifd;
                printf("new client connect fd:[%d] conn_amount:[%d],ip:[%s],port:[%d]\n",fd_cli[i],conn_amount,inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
                if(clifd > maxfd);
                maxfd = clifd;
            }
            else
            {
                printf("max connections,exit\n");
                send(clifd,"sorry",6,0);
                close(clifd);
                break;
            }
        }
        if(FD_ISSET(0,&rfds))
        {
            bzero(buf,MAXBUF + 1);        
            fgets(buf,MAXBUF,stdin);
            if(!strncasecmp(buf,"quit",4))
            {
                printf("i will quit!\n");
                break;
            }
            for(i = 0;i < conn_amount;i++)
            {
                len = send(fd_cli[i],buf,strlen(buf)-1,0);
                if(len > 0)
                    printf("server send successful,%d bytes\n",len);
                else
                {
                    printf("send failed\n");
                    break;
                }
            }
        }
    }
        showclient();
    }


    for(i = 0;i < BACKLGO;i++)
    {
        if(fd_cli[i] != 0)
        {
            close(fd_cli[i]);
        }
    }
    close(serverfd);
    return 0;    
}

客户端代码

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/time.h>
#include<sys/types.h>


#define MAXBUF 512

int main(int argc,char* argv[])
{
    int clifd,len;
    struct sockaddr_in serveraddr;
    char buf[MAXBUF + 1];
    fd_set rfds;
    struct timeval tv;
    int ret,maxfd = -1;
    
    if(argc != 3)
    {
        printf("usage error input ip port\n");
        exit(-1);
    }
    if((clifd = socket(AF_INET,SOCK_STREAM,0)) < 0)
    {
        perror("socket");
        exit(-1);
    }
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    
    if(inet_aton(argv[1],(struct in_addr*)&serveraddr.sin_addr.s_addr) == 0)
    {
        perror("inet_aton");
        exit(-1);
    }
    if(connect(clifd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)) != 0)
    {
        perror("connect");
        exit(-1);
    }
    printf("client is ready...\n");
    
    while(1)
    {
        FD_ZERO(&rfds);
        FD_SET(0,&rfds);
        FD_SET(clifd,&rfds);
        maxfd = clifd;
    
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        
        ret = select(maxfd + 1,&rfds,NULL,NULL,&tv);
        if(ret == -1)
        {
            printf("select %s\n",strerror(errno));
            break;
        }
        else if( ret == 0)
                continue;
        else
        {
            if(FD_ISSET(clifd,&rfds))
            {
                bzero(buf,MAXBUF + 1);
                len = recv(clifd,buf,MAXBUF,0);
                if(len > 0)
                    printf("client fd[%d] recv %s,%d bytes\n",clifd,buf,len);
                else
                {
                    if(len < 0)
                        printf("client recv failed\n");
                    else
                    {
                        printf("server may quit\n");
                        break;
                    }
                }
            }
            if(FD_ISSET(0,&rfds))
            {
                bzero(buf,MAXBUF + 1);
                fgets(buf,MAXBUF,stdin);
                if(!strncasecmp(buf,"quit",4))
                {
                    printf("client will quit\n");
                    break;                    
                }
                len = send(clifd,buf,strlen(buf)-1,0);
                if(len > 0)
                {
                    printf("client send successful %d bytes\n",len);
                }
                else
                        printf("send failed\n");
            }    
        }                
    }
    close(clifd);
    return 0;
}




原创粉丝点击