您的位置:首页 > 运维架构 > Linux

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

2017-08-09 13:10 363 查看
与多进程和多线程技术相比,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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: