柳大的Linux游记·基础篇(5)select IO复用机制
来源:互联网 发布:淘宝天猫网店交易平台 编辑:程序博客网 时间:2024/05/17 04:53
柳大的Linux游记·基础篇(5)select IO复用机制
- Author: 柳大·Poechant(钟超)
- Blog: blog.CSDN.net/Poechant
- Email: zhongchao.ustc#gmail.com (#->@)
- Date: March 13th, 2012
- Copyright © 柳大·Poechant
1 基本原理
注:select 原理图,摘自 IBM iSeries 信息中心。
1 数据结构与函数原型
1.1 select
- 函数原型
int select( int nfds, fd_set *readset, fd_set *writeset, fd_set* exceptset, struct timeval *timeout );
- 头文件
select
位于:#include <sys/select.h>
struct timeval
位于:#include <sys/time.h>
- 返回值
返回对应位仍然为1的fd的总数。
- 参数
- nfds:第一个参数是:最大的文件描述符值+1;
- readset:可读描述符集合;
- writeset:可写描述符集合;
- exceptset:异常描述符;
- timeout:select 的监听时长,如果这短时间内所监听的 socket 没有事件发生。
1.2 fd_set
1.2.1 清空描述符集合
FD_ZERO(fd_set *)
1.2.2 向描述符集合添加指定描述符
FD_SET(int, fd_set *)
1.2.3 从描述符集合删除指定描述符
FD_CLR(int, fd_set *)
1.2.4 检测指定描述符是否在描述符集合中
FD_ISSET(int, fd_set *)
1.2.5 描述符最大数量
#define FD_SETSIZE 1024
1.3 描述符集合
可读描述符集合中可读的描述符,为1,其他为0;可写也类似。异常描述符集合中有异常等待处理的描述符的值为1,其他为0。
1.4 ioctl
函数原型:
int ioctl(int handle, int cmd,[int *argdx, int argcx]);
头文件:
#include <sys/ioctl.h>
返回值:
- 0 - 成功
- 1 - 失败
2 示例
程序各部分的解释在注释中。
#include <sys/socket.h>#include <string.h>#include <sys/time.h>#include <netinet/in.h>#include <sys/ioctl.h>#include <stdlib.h>#include <errno.h>#include <stdio.h>#include <unistd.h>#define TRUE 1#define FALSE 0int main(int argc, char *argv[]){ int i, len, rc, on = TRUE; int listen_sd, new_sd = 0, max_sd; int desc_ready; char buffer[80]; int close_conn, end_server = FALSE; struct sockaddr_in server_addr; struct timeval timeout; struct fd_set master_set, working_set; // Listen listen_sd = socket(AF_INET, SOCK_STREAM, 0); if (listen_sd < 0) { perror("socket() failed"); exit(-1); } // Set socket options rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); if (rc < 0) { perror("setsockopt() failed"); close(listen_sd); exit(-1); } // Set IO control rc = ioctl(listen_sd, FIONBIO, (char *) &on); if (rc < 0) { perror("ioctl() failed"); close(listen_sd); exit(-1); } // Bind memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(atoi(argv[1])); rc = bind(listen_sd, (struct sockaddr *) &server_addr, sizeof(server_addr)); if (rc < 0) { perror("bind() failed\n"); close(listen_sd); exit(-1); } // Listen rc = listen(listen_sd, 32); if (rc < 0) { perror("listen() failed\n"); close(listen_sd); exit(-1); } // Intialize sd set FD_ZERO(&master_set); max_sd = listen_sd; FD_SET(listen_sd, &master_set); timeout.tv_sec = 3 * 60; timeout.tv_usec = 0; // Start do { // Copy master_set into working_set memcpy(&working_set, &master_set, sizeof(master_set)); printf("Waiting on select()...\n"); rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout); if (rc < 0) { perror(" select() failed\n"); break; } if (rc == 0) { printf(" select() timed out. End program.\n"); break; } desc_ready = rc; // number of sds ready in working_set // Check each sd in working_set for (i = 0; i <= max_sd && desc_ready > 0; ++i) { // Check to see if this sd is ready if (FD_ISSET(i, &working_set)) { --desc_ready; // Check to see if this is the listening sd if (i == listen_sd) { printf(" Listeing socket is readable\n"); do { // Accept new_sd = accept(listen_sd, NULL, NULL); // Nothing to be accepted if (new_sd < 0) { // All have been accepted if (errno != EWOULDBLOCK) { perror(" accept() failed\n"); end_server = TRUE; } break; } // Insert new_sd into master_set printf(" New incoming connection - %d\n", new_sd); FD_SET(new_sd, &master_set); if (new_sd > max_sd) { max_sd = new_sd; } } while (new_sd != -1); } // This is not the listening sd else { close_conn = FALSE; printf(" Descriptor %d is avaliable\n", i); do { rc = recv(i, buffer, sizeof(buffer), 0); // Receive data on sd "i", until failure occurs if (rc < 0) { // Normal failure if (errno != EWOULDBLOCK) { perror(" recv() failed\n"); close_conn = TRUE; } break; } // The connection has been closed by the client if (rc == 0) { printf(" Connection closed\n"); close_conn = TRUE; break; } /* Receiving data succeeded and echo it back the to client */ len = rc; printf(" %d bytes received\n", len); rc = send(i, buffer, len, 0); if (rc < 0) { perror(" send() failed"); close_conn = TRUE; break; } } while (TRUE); // If unknown failure occured if (close_conn) { // Close the sd and remove it from master_set close(i); FD_CLR(i, &master_set); // If this is the max sd if (i == max_sd) { // Find the max sd in master_set now while (FD_ISSET(max_sd, &master_set) == FALSE) { --max_sd; } } // End of if (i == max_sd) } // End of if (close_conn) } } } } while (end_server == FALSE); /* Close each sd in master_set */ for (i = 0; i < max_sd; ++i) { if (FD_ISSET(i, &master_set)) { close(i); } } return 0;}
参考
- http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzab6%2Frzab6xnonblock.htm
-
转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant
-
- 柳大的Linux游记·基础篇(5)select IO复用机制
- 柳大的Linux游记·基础篇(5)select IO复用机制
- Linux的select IO复用机制
- Linux中select IO复用机制
- Linux中select IO复用机制
- Linux中select IO复用机制
- Linux中select IO复用机制
- select IO复用机制
- select IO复用机制
- Linux中select IO多路复用机制
- Linux中select IO多路复用机制
- linux基础——linux下多路IO复用接口之select/poll
- Linux IO复用之select
- Linux IO复用模型之select
- linux io复用之select
- linux IO多路复用机制(select、poll、epoll)及5种IO模型
- Linux的异步IO机制(转)
- Linux的异步IO机制(转)
- Linux Shell常用技巧
- Quartz在Spring中动态设置cronExpression (spring设置动态定时任务)
- B树算法应用实例
- 一个简单的文件共享工程 -- 总结
- 你该怎么学——韩顺平
- 柳大的Linux游记·基础篇(5)select IO复用机制
- MacPC键盘对应快捷键一览
- MYSQL备份方法的总结
- Makefile文件
- 学习vb感受
- JAVA Sting int互转的注意
- 深入理解C++中的mutable关键字
- Spring动态定时器
- Struts2入门基础之Action详解(四)