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. SQL Server 2012 T-SQL 新特性

    序列 Sequence SQL Server 现在将序列当成一个对象来实现,创建一个序列的例子语法如下: CREATE SEQUENCE DemoSequence START WITH 1 INCRE ...

  2. WPF中找不到Image或者Image不是Drawing系列

    WPF中默认没有引用WinForm里面的一些东西,都是用它自带的那一套,但又不能完全脱离,所以有的时候比较蛋疼

  3. 深入理解javascript作用域系列第四篇——块作用域

    × 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...

  4. PHP获取图片宽度高度、大小尺寸、图片类型、用于布局的img属性

    //php自带函数 getimagesize()$img_info = getimagesize('tomener.jpg'); echo '<pre>'; print_r($img_in ...

  5. 转载--How to Install VMware Tools on CentOS 6.3

    源地址:http://www.ehowstuff.com/how-to-install-vmware-tools-on-centos-6-3/ VMware Tools is a group of u ...

  6. Android中的内存储、外存储概念、文件操作与PC端的有些不同

    其实安卓文件的操作和java在pc环境下的操作并无二致,之所以需要单独讲解是因为安卓系统提供了不同于pc的访问文件系统根路径的api,同时对一个应用的私有文件做了统一的管理.初学者在这部分感到很容易混 ...

  7. Redis持久化方法对比分析

    1.前言 最近在项目中使用到Redis做缓存,方便多个业务进程之间共享数据.由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能, ...

  8. Windows下elasticsearch插入数据报错!

    按照官方文档操作,但是windows下有些不同,它不认识单引号',因此如果这样操作,就会报错: C:\Users\neusoft>curl localhost:9200/b1/b2/1 -d { ...

  9. apache(nginx)+django+virutalenv(virtualenvwrapper)+gunicorn+supervisor配置高效web环境

    前言 django的调试模式配置简单,用于测试十分方便,但众所周知,这个只适合于调试,生产上运行效率十分低下. 后来考虑用nginx+uwsgi的模式进行,但之前配置过apache+wsgi的方式,感 ...

  10. Spring MVC 原理介绍(执行流程)

    Spring MVC工作流程图   图一   图二    Spring工作流程描述       1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServle ...