免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6661 | 回复: 6
打印 上一主题 下一主题

讨论:select()用法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-03-26 11:53 |只看该作者 |倒序浏览
我正在读wrox系例中的Beginning Linux Programming,其中socket编程中,针对select用法所举的例子百思不得其解,特请大家帮忙分析指正。

例子是关于一个服务器程序实现对多个客户同时处理的

server1.c 用fork()实现
server2.c 用select()实现

server1.c 主要代码如下:

  1.     while(1) {
  2.         char ch;

  3.         printf("server waiting\n");

  4. /*  Accept connection.  */

  5.         client_len = sizeof(client_address);
  6.         client_sockfd = accept(server_sockfd,
  7.             (struct sockaddr *)&client_address, &client_len);

  8. /*  Fork to create a process for this client and perform a test to see
  9.     whether we're the parent or the child.  */

  10.         if(fork() == 0) {

  11. /*  If we're the child, we can now read/write to the client on client_sockfd.
  12.     The five second delay is just for this demonstration.  */

  13.             read(client_sockfd, &ch, 1);
  14.             sleep(5);
  15.             ch++;
  16.             write(client_sockfd, &ch, 1);
  17.             close(client_sockfd);
  18.             exit(0);
  19.         }

  20. /*  Otherwise, we must be the parent and our work for this client is finished.  */

  21.         else {
  22.             close(client_sockfd);
  23.         }
  24.     }

复制代码


server2.c 主要代码如下:


  1.     FD_ZERO(&readfds);
  2.     FD_SET(server_sockfd, &readfds);

  3. /*  Now wait for clients and requests.
  4.     Since we have passed a null pointer as the timeout parameter, no timeout will occur.
  5.     The program will exit and report an error if select returns a value of less than 1.  */

  6.     while(1) {
  7.         char ch;
  8.         int fd;
  9.         int nread;

  10.         testfds = readfds;

  11.         printf("server waiting\n");
  12.         result = select(FD_SETSIZE, &testfds, (fd_set *)0,
  13.             (fd_set *)0, (struct timeval *) 0);

  14.         if(result < 1) {
  15.             perror("server5");
  16.             exit(1);
  17.         }

  18. /*  Once we know we've got activity,
  19.     we find which descriptor it's on by checking each in turn using FD_ISSET.  */

  20.         for(fd = 0; fd < FD_SETSIZE; fd++) {
  21.             if(FD_ISSET(fd,&testfds)) {

  22. /*  If the activity is on server_sockfd, it must be a request for a new connection
  23.     and we add the associated client_sockfd to the descriptor set.  */

  24.                 if(fd == server_sockfd) {
  25.                     client_len = sizeof(client_address);
  26.                     client_sockfd = accept(server_sockfd,
  27.                         (struct sockaddr *)&client_address, &client_len);
  28.                     FD_SET(client_sockfd, &readfds);
  29.                     printf("adding client on fd %d\n", client_sockfd);
  30.                 }

  31. /*  If it isn't the server, it must be client activity.
  32.     If close is received, the client has gone away and we remove it from the descriptor set.
  33.     Otherwise, we 'serve' the client as in the previous examples.  */

  34.                 else {
  35.                     ioctl(fd, FIONREAD, &nread);

  36.                     if(nread == 0) {
  37.                         close(fd);
  38.                         FD_CLR(fd, &readfds);
  39.                         printf("removing client on fd %d\n", fd);
  40.                     }

  41.                     else {
  42.                         read(fd, &ch, 1);
  43.                         sleep(5);
  44.                         printf("serving client on fd %d\n", fd);
  45.                         ch++;
  46.                         write(fd, &ch, 1);
  47.                     }
  48.                 }
  49.             }
  50.         }
  51.     }

复制代码


文章的意思是,server2.c 既能借助select()实现server1.c 的及时处理多客户的请求,又避免了server1.c 中有fork()的资源浪费,
问题是:
  
    我看不出server2.c 中的代码实现有任何能 及时处理 多客户请求的地方。
和以下最简单的代码效率是相同的

  1.     listen(server_sockfd, 5);
  2.     while(1) {
  3.         char ch;

  4.         printf("server waiting\n");

  5. /*  Accept a connection.  */

  6.         client_len = sizeof(client_address);
  7.         client_sockfd = accept(server_sockfd,
  8.             (struct sockaddr *)&client_address, &client_len);

  9. /*  We can now read/write to client on client_sockfd.  */

  10.         read(client_sockfd, &ch, 1);
  11.         ch++;
  12.         write(client_sockfd, &ch, 1);
  13.         close(client_sockfd);
  14.     }
复制代码


大家分析一下,select()的作用到底在哪里?
还有select()一般都用在何处场合?

论坛徽章:
0
2 [报告]
发表于 2003-03-26 13:04 |只看该作者

讨论:select()用法

up,

兄弟们,看看呀,代码非常易懂。

论坛徽章:
0
3 [报告]
发表于 2003-03-26 17:56 |只看该作者

讨论:select()用法

select 用于等待文件描述符变成非阻塞状态(可读、可写、有异常)

第一个参数是文件描述符的最大数目+1   如你的文件描述符是 1 5 15 ,那么就是写16了

第二、三、四参数是要等待的描述符数组
分别表示当可读时、可写时、有异常时

如果你关心某一描述符数组的某一状态,就把它写到对应参数中去
不关心就写NULL

5等待时间。

返回:-1出错0 超时
>;0 满足条件的描述符数目


更多可以自己看代码
或是使用GOOGLE查找

论坛徽章:
0
4 [报告]
发表于 2003-03-27 09:09 |只看该作者

讨论:select()用法

谢谢斑主,
一般select()都用于哪些实际工作中呢?

论坛徽章:
0
5 [报告]
发表于 2003-03-27 09:27 |只看该作者

讨论:select()用法

select 可以实现微妙级的延时

select 主要是来组成一组描述符组,然后,判断这些描述符是否可写,读,异常

论坛徽章:
0
6 [报告]
发表于 2003-03-27 09:28 |只看该作者

讨论:select()用法

一般是用来网络通信的,建立连接后检测套接字是否有数据可读,或者非阻塞方式connect返回后,用select检测套接字是否可写入在判断连接是否建立,还可以用作定时器……,我只有上面的几种用法,欢迎补充。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
7 [报告]
发表于 2003-03-27 11:18 |只看该作者

讨论:select()用法

select是针对描述符(注意是描述符,包括socket描述符、文件描述符等unix维护的描述福)而言的,主要的作用是用来做多路复用,类似的函数如poll也能实现该功能。当应用程序需要对多种描述符的状态做处理的时候,可以考虑使用select实现,例如应用需要同时处理来自STDIN_FILENO和多个不同socket_read的描述符可读状态,这时候便可以用select来实现多路复用,select函数的具体参数含义和返回值无双斑竹做了详细的描述,其他的人描述了select能够处理的主要三种类型,可读、可写和异常。(另外select可实现较为精确的定时器,可通过设置监测描述符参数为NULL来实现)。大多数得unix系统提供了专门的函数配合select来实现复用,这些函数是FD_CLR(fd, &amp;fdset)、 FD_ISSET(fd, &amp;fdset)、FD_SET(fd, &amp;fdset)、FD_ZERO(&amp;fdset),fd是一个描述符,一般用int来实现兼容性(注意在做STD类型的文件描述符的时候,可以通过fileno转化),fdset是fd_set类型,fd_set是为select设计的数据类型,实际上函数FD_ISSET是通过fd_set的每个bit(注意是比特)变化来监测某一被set的描述符状态变化。
需要说明的一点是该函数不是原子调用,在select阻塞的过程中(如何阻塞通过类型为struct timeval得参数来设置的),需要应用来处理系统发生的任何异常,否则你会发现select可能并没有按照你的意愿去做。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP