select服務器編寫

select與多進程/多線程服務器進行對比

優點

1)不需要建立多個線程、進程就可以實現一對多的通信。
2)可以同時等待多個文件描述符,效率比起多進程多線程來說要高很多。
3)select()的可移植性更好,在某些Unix系統上不支持poll()
4)select() 對於超時值提供了更好的精度:微秒,而poll是毫秒

缺點

1)每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大 ,循環次數有點多;
2)同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大 。
3)select支持的文件描述符數量太小了,默認是1024;

select 整體實現:

/*************************************************************************
    > File Name: select.c
    > Author:Steve 
    > Mail:[email protected] 
    > Created Time: Tue 01 Aug 2017 09:50:09 AM PDT
 ************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/select.h>
#include<sys/time.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SIZE sizeof(fd_set)*8
//select
void Usage(char* proc)
{
    printf("Usage:%s[local ip][local port]\n",proc);
}

int startUp(char* ip,int port)
{
    //create   bind listen 
    //
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("sock");
        exit(1);
    }

    int opt=1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_addr.s_addr=inet_addr(ip);
    local.sin_port=htons(port);


    if(bind(sock,(struct sockaddr *)&local,sizeof(local))<0)
    {
        perror("bind");
        exit(2);
    }
    if(listen(sock,10)<0)
    {
        perror("listen");
        exit(3);
    }
    return sock;
}

int fds[SIZE];

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

    if(argc!=3)
    {
        Usage(argv[0]);
        return 1;
    }

   int listen_socket=startUp(argv[1],atoi(argv[2]));
    printf("listen_fd is %d\n",listen_socket);

    //fd_set rfds;
    //FD_SET(listen_socket,&rfds);

     int nums=SIZE;
    memset(fds,-1,nums);
    fds[0]=listen_socket;
    while(1)
    {
        //we need everytime to renew the rfds  by fds
        int i=0;
        int max=-1;
        struct timeval timeout={1,0};///1s
        fd_set rfds;
        FD_ZERO(&rfds);
        for(;i<nums;i++)
        {
            if(fds[i]!=-1)
            {
                if(max<fds[i])
                {
                    max=fds[i];
                }
                FD_SET(fds[i],&rfds);
            }

        }
        switch(select(max+1,&rfds,NULL,NULL,NULL))
               {
                   case 0 :
                   printf("timeout..\n");
                   break;
                   case -1:
                   perror("select");
                   break;
                   default:
                   //at least a fd is ready
                   for(i=0;i<nums;i++)
                   {
                       if(i==0&&FD_ISSET(listen_socket,&rfds))
                       {
                           struct sockaddr_in new_client;
                           socklen_t len=sizeof(new_client);
                           //  we can accept   new client
                           int client_sock=accept(listen_socket,\
                            (struct sockaddr*)&new_client,&len);
                           if(client_sock<0)
                           {
                               perror("accept:");
                               continue;
                           }
                          printf("get a new client [%s][%d]\n",inet_ntoa(new_client.sin_addr),ntohs(new_client.sin_port)); 
                           int i;
                           for(i=1;i<nums;i++)
                           {
                               if(fds[i]==-1)
                               {
                                   break;
                               }
                           }
                           if(i==nums)
                           {   
                               printf("fd is full\n");
                               close(client_sock);
                           }
                           else
                           {
                               fds[i]=client_sock;
                           }
                           continue;
                       }
                       else if(i!=0&&FD_ISSET(fds[i],&rfds))
                       {
                           //read& write
                           char buf[1024];
                           ssize_t s=read(fds[i],buf,sizeof(buf)-1);
                           if(s>0)
                           {
                               buf[s]=0;
                               printf("client #%s\n",buf);
                              write(fds[i],buf,strlen(buf));
                           }else if(s==0)
                           {
                               printf("client is quit!\n");
                               //connection failed
                               close(fds[i]);
                               fds[i]=-1;
                           }
                           else{
                               perror("read");
                               close(fds[i]);
                               fds[i]=-1;
                           }
                       }else{
                           continue;
                       }
                    }
                   break;

        }
    }
    close(listen_socket);
    return 0;
}
/*************************************************************************
    > File Name: client.c
    > Author:Steve 
    > Mail:[email protected] 
    > Created Time: Tue 01 Aug 2017 07:54:55 PM PDT
 ************************************************************************/

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

void Usage(char* proc)
{
    printf("Usage:%s[local ip][local port]\n",proc);
}

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

    if(argc!=3)
    {
        Usage(argv[0]);
        return 1;
    }

    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        return 2;
    }

    struct sockaddr_in server;
    server.sin_family=AF_INET;
    server.sin_addr.s_addr=inet_addr(argv[1]);
    server.sin_port=htons(atoi(argv[2]));

    socklen_t len=sizeof(server);
    if(connect(sock,(struct sockaddr*)&server,len)<0)
    {
        perror("connect");
        return 3;
    }

    printf("connect is successfully\n");

    char buf[1024];

    while(1)
    {
        memset(buf,0,sizeof(buf));
        printf("Please input:");
        fflush(stdout);
        ssize_t s=read(0,buf,sizeof(buf)-1);
        if(s>0)
        {
            buf[s-1]=0;
            write(sock,buf,strlen(buf));
        }
        ssize_t _s=read(sock,buf,sizeof(buf)-1);
        if(_s>0)
        {
         buf[_s]=0;
       printf("server echo:%s\n",buf);
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章