Select服务器

来源:互联网 发布:淘宝网电脑端描述 编辑:程序博客网 时间:2024/05/17 07:09

select

#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<string.h>int array_fds[1024];static void Usage(const char *proc){    printf("Usage: %s [local_ip] [local_port]\n",proc);}int startup(char *_ip, int _port){    int sock = socket(AF_INET,SOCK_STREAM,0);    if(sock < 0)    {        perror("sock");        exit(2);    }    int flag = 1;    setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));    struct sockaddr_in local;    local.sin_family = AF_INET;    local.sin_port = htons(_port);    local.sin_addr.s_addr = inet_addr(_ip);    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)    {        perror("bind");        exit(3);    }    if(listen(sock,10)<0)    {        perror("listen");        exit(4);    }    return sock;}int main(int argc,char* argv[]){    if(argc != 3)    {        Usage(argv[0]);        return 0;    }    int listenSock = startup(argv[1],atoi(argv[2]));    int maxfd = 0;    fd_set rfds;    int array_size = sizeof(array_fds)/sizeof(array_fds[0]);    array_fds[0] = listenSock;    int i = 1;    for(;i < array_size;i++)    {        array_fds[i] = -1;    }    while(1){        struct timeval _timeout = {0,0};        FD_ZERO(&rfds);        maxfd = -1;        for(i = 0;i<array_size;i++){            if(array_fds[i] > 0){                FD_SET(array_fds[i],&rfds);                if(array_fds[i] > maxfd){                    maxfd = array_fds[i];                }            }        }        switch(select(maxfd+1,&rfds,NULL,NULL,NULL/*&_timeout*/)){            case 0:                printf("timeout...\n");                break;            case -1:                perror("select");                break;            default:                {                    int j = 0;                    for(;j < array_size;j++){                        if(array_fds[j]<0){                            continue;                        }                        if(j == 0&&FD_ISSET(array_fds[j],&rfds)){                            struct sockaddr_in client;                            socklen_t len = sizeof(client);                            int new_fd = accept(array_fds[j],\                                    (struct sockaddr*)&client,&len);                            if(new_fd < 0){                                perror("accept");                                continue;                            }                            else{                                printf("get a new client: (%s:%d)\n",\                                        inet_ntoa(client.sin_addr),\                                        ntohs(client.sin_port));                                int k = 1;                                for(;k < array_size;k++){                                    if(array_fds[k] < 0){                                        array_fds[k] = new_fd;                                        break;                                    }                                }                                if(k == array_size){                                    close(new_fd);                                }                            }                        }                        else if(j != 0&&\                                FD_ISSET(array_fds[j],&rfds))                        {                            char buf[10240];                            ssize_t s = read(array_fds[j],buf,sizeof(buf)-1);                            if(s>0)                            {                                buf[s] = 0;                                printf("client say: %s\n",buf);                            }                            else if(s == 0)                            {                                printf("client quit!\n");                                close(array_fds[j]);                                array_fds[j] = -1;                            }                            else                            {                                perror("read");                                close(array_fds[j]);                                array_fds[j] = -1;                            }                        }                        else                        {                        }                    }                }                break;        }    }    return 0;}

client

#include<stdio.h>  #include<sys/types.h>  #include<netinet/in.h>  #include<arpa/inet.h>  #include<sys/socket.h>  #include<stdlib.h>  #include<string.h>  #include<strings.h>  #include<sys/stat.h>  #include<unistd.h>  static void Usage(char * proc)  {      printf("Usage : %s [ip] [port]\n");  }  int main(int argc, char* argv[])  {      if(argc != 3)      {          Usage(argv[0]);          return 1;      }      int sock = socket(AF_INET, SOCK_STREAM, 0);      struct sockaddr_in peer;      peer.sin_family = AF_INET;      peer.sin_port = htons(atoi(argv[2]));      peer.sin_addr.s_addr = inet_addr(argv[1]);      if(connect(sock, (struct sockaddr*)&peer, sizeof(peer)) < 0)      {          perror("connect");          return 2;      }      char buf[10240];      //int sfd = dup(STDOUT_FILENO);      while(1)      {          printf("Please Enter : ");          fflush(stdout);          ssize_t s = read(0, buf, sizeof(buf)-1);          int sfd = dup(STDOUT_FILENO);          if(s > 0)          {              buf[s-1] = 0;              //write(sock, buf, strlen(buf));              //输出重定向              //close(1);             // int new_fd = dup(sock);             int new_fd = dup2(sock, 1);              if(new_fd == -1)              {                 perror("dup()");                 return -1;              }              printf("%s",buf);              fflush(stdout);              //恢复stdout              dup2(sfd, STDOUT_FILENO);              ssize_t _s = read(sock, buf, sizeof(buf)-1);              if(_s > 0)              {                 buf[_s] = 0;                 printf("sever # %s \n", buf);              }          }      }      close(sock);      return 0;  }  

总结select服务器优缺点,与多进程/多线程服务器进行对比:
使用select注意事项:
1.要将sock_fd加入到maxfd+1中,要不就无法检测到网络连接,会一直阻塞在select语句
2.通过存储每次连接的描述符,设置FD_SET函数,在遍历的去判断FD_ISSET处理。
3.我们可以看到select每次有数据到来时,需要遍历的去寻找所有可用的描述符,来判断其是否满足处理的条件。
4.select的通知机制,轮询的去查看是否在maxfd+1内有满足条件的描述符
select优缺点:
与多进程/多线程服务器进行对比 它的优点在于:
1、不需要建立多个线程、进程就可以实现一对多的通信。
2、可以同时等待多个文件描述符,效率比起多进程多线程来说要高很多。
3、select()的可移植性更好,在某些Unix系统上不支持poll()
4、select() 对于超时值提供了更好的精度:微秒,而poll是毫秒

与多进程/多线程服务器进行对比 它的缺点在于:
1、每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 ,循环次数有点多;
2、同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 。
3、select支持的文件描述符数量太小了,默认是1024;

原创粉丝点击