select函数:

#include <sys/select.h>
#include <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);

参数含义:

  • nfds:一个整型变量,它比所有文件描述符集合中的文件描述符的最大值大1。使用select的时候,必须计算最大值的文件描述符的值,将值通过nfds传入。
  • readfds:这个文件描述符集合监视文件集中的任何文件是否有数据可读,当select()返回的时候,readfds将清除其中不可读的文件描述符,只留下可读的文件描述符,即可以被recv()、read()等进行读操作。
  • writefds:这个文件描述符集合监视文件集中的任何文件是否有数据可写,当select()返回的时候,readfds将清除其中不可写的文件描述符,只留下可写的文件描述符,即可以被send()、write()等进行读操作。
  • exceptfds:这个文件集合将监视文件中的任何文件是否发生错误,其实,它还能用于监视带外数据OOB,带外数据使用MSG_OOB标志发送到套接字上。当select()返回时,readfds将清除其中的其他文件描述符,只留下可读的OOB数据。
  • timeout:设置在select()所监视的文件集合中的事件没有发生时,最长的等待时间,当超过这个时间时,函数返回。当超时返回为NULL时,表示阻塞操作,会一直等待,直到某个监视的文件集中的某个文件描述符符合返回条件。当timeout的值为0时,select()会立即返回。
  • sigmask:信号

返回值:

当返回大于0的正值:监视的文件集合中的文件描述符符合上述要求。

当等于0时:超时。

当为-1时:发生错误

struct timeval结构:

struct timeval
{
time_t tv_sec; //秒
long tv_usec; // 微秒,即1/1000000s
}

另外,还有4个宏操作文件描述符的集合:

FD_ZERO():清理文件描述符集合;

FD_SET():向某个文件描述符集合中加入文件描述符;

FD_CLR():从某个文件描述符集合中取某个文件描述符;

FD_ISSET():测试某个文件描述符是否为某个集合中的一员。

注:文件描述符的集合存在最大的限制,其最大值为FD_SETSIZE,当超出最大值时,发生不可预料的事。同时,可以修改这个值,但是监视集合的效率会降低,是因为select()轮询是线性的。在这里,有个更加牛B的的函数,请查看epoll:epoll没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于2048, 一般来说这个数目和系统内存关系很大。最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。在内存拷贝上,epoll在这点上使用了“共享内存”,这个内存拷贝也省略了。

附加:使用select()写的IO复用循环服务器模型的例子

 #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/select.h>
#define BUFFLEN 1024
#define SERVER_PORT 8888
#define BACKLOG 5
#define CLIENTNUM 1024/*最大支持客户端数量*/ /*可连接客户端的文件描述符数组*/
int connect_host[CLIENTNUM];
int connect_number = ; //处理客户端请求函数
static void *handle_request(void *argv)
{
time_t now; /*时间*/
char buff[BUFFLEN];/*收发数据缓冲区*/
int n = ; int maxfd = -;/*最大侦听文件描述符*/
fd_set scanfd; /*侦听描述符集合*/
struct timeval timeout; /*超时*/
timeout.tv_sec = ; /* 阻塞1秒后超时返回 */
timeout.tv_usec = ; int i = ;
int err = -;
for(;;)
{
/*最大文件描述符值初始化为-1*/
maxfd = -;
FD_ZERO(&scanfd);/*清零文件描述符集合*/
for(i=;i<CLIENTNUM;i++)/*将文件描述符放入集合*/
{
if(connect_host[i] != -)/*合法的文件描述符*/
{
FD_SET(connect_host[i], &scanfd);/*放入集合*/
if(maxfd < connect_host[i])/*更新最大文件描述符值*/
{
maxfd = connect_host[i];
}
}
}
/*select等待*/
err = select(maxfd + , &scanfd, NULL, NULL, &timeout) ;
switch(err)
{
case :/*超时*/
break;
case -:/*错误发生*/
break;
default:/*有可读套接字文件描述符*/
if(connect_number<=)
break;
for(i = ;i<CLIENTNUM;i++)
{
/*查找激活的文件描述符*/
if(connect_host[i] != -)
if(FD_ISSET(connect_host[i],&scanfd))
{
memset(buff, , BUFFLEN);/*清零*/
n = recv(connect_host[i], buff, BUFFLEN,);/*接收发送方数据*/
if(n > && !strncmp(buff, "TIME", ))/*判断是否合法接收数据*/
{
memset(buff, , BUFFLEN);/*清零*/
now = time(NULL);/*当前时间*/
sprintf(buff, "%24s\r\n",ctime(&now));/*将时间拷贝入缓冲区*/
send(connect_host[i], buff, strlen(buff),);/*发送数据*/
}
/*更新文件描述符在数组中的值*/
connect_host[i] = -;
connect_number --; /*客户端计数器减1*/
/*关闭客户端*/
close(connect_host[i]);
}
}
break;
}
} return NULL;
} //处理客户端连接函数
static void *handle_connect(void *argv)
{
int s_s = *((int*)argv) ;/*获得服务器侦听套接字文件描述符*/
int s_c = -;/*连接客户端文件描述符*/
struct sockaddr_in from;
int len = sizeof(from);
/*接收客户端连接*/
for(;;)
{
int i = ;
int s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端的请求*/
printf("a client connect, from:%s\n",inet_ntoa(from.sin_addr));
/*查找合适位置,将客户端的文件描述符放入*/
for(i=;i<CLIENTNUM;i++)
{
if(connect_host[i] == -)/*找到*/
{
/*放入*/
connect_host[i]= s_c; /*客户端计数器加1*/
connect_number ++;
/*继续轮询等待客户端连接*/
break;
}
}
}
return NULL;
} int main(int argc, char *argv[])
{
int s_s; /*服务器套接字文件描述符*/
struct sockaddr_in local; /*本地地址*/
int i = ;
memset(connect_host, -, CLIENTNUM); /*建立TCP套接字*/
s_s = socket(AF_INET, SOCK_STREAM, ); /*初始化地址接哦股*/
memset(&local, , sizeof(local));/*清零*/
local.sin_family = AF_INET;/*AF_INET协议族*/
local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
local.sin_port = htons(SERVER_PORT);/*服务器端口*/ /*将套接字文件描述符绑定到本地地址和端口*/
int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
err = listen(s_s, BACKLOG);/*侦听*/ pthread_t thread_do[];/*线程ID*/
/*创建线程处理客户端连接*/
pthread_create(&thread_do[],/*线程ID*/
NULL,/*属性*/
handle_connect,/*线程回调函数*/
(void*)&s_s); /*线程参数*/
/*创建线程处理客户端请求*/
pthread_create(&thread_do[],/*线程ID*/
NULL,/*属性*/
handle_request,/*线程回调函数*/
NULL); /*线程参数*/
/*等待线程结束*/
for(i=;i<;i++)
pthread_join(thread_do[i], NULL); close(s_s); return ;
}
作者:orange1438
出处:http://www.cnblogs.com/orange1438/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

IO复用_select函数的更多相关文章

  1. IO复用_epoll函数

    由于poll()和select()的局限,2.6内核以上引用了event poll机制(就是说的epoll),虽然比前2个实现复杂得多,epoll解决了它们共有的基本性能问题,并增加了新的特性. po ...

  2. 【Unix网络编程】chapter6 IO复用:select和poll函数

    chapter6 6.1 概述 I/O复用典型使用在下列网络应用场合. (1):当客户处理多个描述符时,必须使用IO复用 (2):一个客户同时处理多个套接字是可能的,不过不叫少见. (3):如果一个T ...

  3. Linux网络编程-IO复用技术

    IO复用是Linux中的IO模型之一,IO复用就是进程预先告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理,从而不会在单个IO上阻塞了.Linux中,提 ...

  4. Libevent的IO复用技术和定时事件原理

    Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易 ...

  5. IO复用三种方式

    简介 IO复用技术,简单来说就是同时监听多个描述符.在没有用到IO复用以前,只能是一个线程或一个 线程去监听,服务端同时有多个连接的时候,需要创建多个线程或者进程.而且,并不是所有的连 接是一直在传输 ...

  6. 高级IO复用应用:聊天室程序

    简单的聊天室程序:客户端从标准输入输入数据后发送给服务端,服务端将用户发送来的数据转发给其它用户.这里采用IO复用poll技术.客户端采用了splice零拷贝.服务端采用了空间换时间(分配超大的用户数 ...

  7. select、poll、epoll三组IO复用

    int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout)//其中n ...

  8. Linux中的IO复用接口简介(文件监视?)

    I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...

  9. IO复用

    IO复用:使得程序能同时监听多个文件描述符 select: select在一段指定的时间内,监听用户感兴趣的文件描述符的 读.写.异常事件. select(int nfds,fd_set* readf ...

随机推荐

  1. JSON学习之一

    1.JSON:JavaScript Object Notation(javaScript对象表示法),JSON是存储和交换文本信息的语法,类似XML:JSON比XML更小,更快,更易解析: { &qu ...

  2. 使用BCP导出导入数据

    bcp 实用工具可以在 Microsoft SQL Server 实例和用户指定格式的数据文件间大容量复制数据. 使用 bcp 实用工具可以将大量新行导入 SQL Server 表,或将表数据导出到数 ...

  3. Huge Page 是否是拯救性能的万能良药?

    本文将分析是否Huge Page在任何条件下(特别是NUMA架构下)都能带来性能提升. 本博客已经迁移至: http://cenalulu.github.io/ 为了更好的体验,请通过此链接阅读: h ...

  4. Cocos2d-x 3.2 学习笔记(四)学习打包Android平台APK!

    从cocos2dx 3.2项目打包成apk安卓应用文件,搭建安卓环境的步骤有点繁琐,但搭建一次之后,以后就会非常快捷! (涉及到3.1.1版本的,请自动对应3.2版本,3.x版本的环境搭建都是一样的) ...

  5. spring源码分析之spring-core asm概述

    ASM是什么? ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to m ...

  6. [Linux] LD_LIBRARY_PATH

    该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径(该路径在默认路径之前查找).若共享库不在缺省路径/lib或者/usr/lib下,就需要指定其他路径.实践中的一种解决方案是, ...

  7. Javascript模块化开发,使用模块化脚本加载工具RequireJS,提高你代码的速度和质量。

    随着前端JavaScript代码越来越重,如何组织JavaScript代码变得非常重要,好的组织方式,可以让别人和自己很好的理解代码,也便于维护和测试.模块化是一种非常好的代码组织方式,本文试着对Ja ...

  8. Windows Azure Cloud Service (42) 使用Azure In-Role Cache缓存(1)Co-located Role

    <Windows Azure Platform 系列文章目录> Update 2016-01-12 https://azure.microsoft.com/zh-cn/documentat ...

  9. java中遇到过的String的一些特性

    1.string对象是final的? String str="asdfdf"; str.replace("as",""); System.o ...

  10. Redis Lua脚本原理

    2.6版本之后支持嵌入Lua脚本,客户端使用Lua脚本,直接在服务器端原子的执行多条命令 Lua脚本执行过程 创建并修改Lua环境 1 创建基础Lua环境 2 载入函数库 3 创建全局表格Lua 4 ...