IO复用_select函数
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函数的更多相关文章
- IO复用_epoll函数
由于poll()和select()的局限,2.6内核以上引用了event poll机制(就是说的epoll),虽然比前2个实现复杂得多,epoll解决了它们共有的基本性能问题,并增加了新的特性. po ...
- 【Unix网络编程】chapter6 IO复用:select和poll函数
chapter6 6.1 概述 I/O复用典型使用在下列网络应用场合. (1):当客户处理多个描述符时,必须使用IO复用 (2):一个客户同时处理多个套接字是可能的,不过不叫少见. (3):如果一个T ...
- Linux网络编程-IO复用技术
IO复用是Linux中的IO模型之一,IO复用就是进程预先告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理,从而不会在单个IO上阻塞了.Linux中,提 ...
- Libevent的IO复用技术和定时事件原理
Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易 ...
- IO复用三种方式
简介 IO复用技术,简单来说就是同时监听多个描述符.在没有用到IO复用以前,只能是一个线程或一个 线程去监听,服务端同时有多个连接的时候,需要创建多个线程或者进程.而且,并不是所有的连 接是一直在传输 ...
- 高级IO复用应用:聊天室程序
简单的聊天室程序:客户端从标准输入输入数据后发送给服务端,服务端将用户发送来的数据转发给其它用户.这里采用IO复用poll技术.客户端采用了splice零拷贝.服务端采用了空间换时间(分配超大的用户数 ...
- select、poll、epoll三组IO复用
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout)//其中n ...
- Linux中的IO复用接口简介(文件监视?)
I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...
- IO复用
IO复用:使得程序能同时监听多个文件描述符 select: select在一段指定的时间内,监听用户感兴趣的文件描述符的 读.写.异常事件. select(int nfds,fd_set* readf ...
随机推荐
- KnockoutJS 3.X API 第四章 表单绑定(7) event绑定
目的 event绑定即为事件绑定,即当触发相关DOM事件的时候回调函数.例如keypress,mouseover或者mouseout等 例如: Mouse over me Details var vi ...
- 一步一步教你安装openstack
openstack,安装的门槛比较高,而且相当麻烦,很多的安装文档作者省了不少安装步骤.这对初学的人带来了很大的麻烦,也许作者轻易节省一步,就会创成后面的安装失败.而且初学者由于对openstack不 ...
- 【转】Windows Phone在隔离存储里存取图片文件
一共两个页面,第一个为MainPage.xaml,代码如下: <!--ContentPanel - place additional content here--> <Grid x: ...
- Android属性动画之ValueAnimation
ValueAnimation是ObjectAnimation类的父类,经过前几天的介绍,相信大家对ObjectAnimation有了 一定的认识,今天就为大家最后介绍一下ValueAnimation, ...
- 关于CPU Cache -- 程序员需要知道的那些事
本文将介绍一些作为程序猿或者IT从业者应该知道的CPU Cache相关的知识.本章从"为什么会有CPU Cache","CPU Cache的大致设计架构",&q ...
- Codrops 优秀教程:CSS 3D Transforms 实现书本效果
这个使用 CSS 3D Transforms 实现创意书本效果的来自 Codrops 网站.你可以看到两种类型的书设计:精装书和平装书.这两个效果都可以很容易地使用 CSS 修改.赶紧体验一下吧. ...
- Azure ARM (3) ARM支持的服务类型
<Windows Azure Platform 系列文章目录> 我们在使用ARM创建资源的时候,首先要确认哪些Azure服务,支持ARM模式. 具体内容,我们可以参考连接:https:// ...
- Windows Azure Cloud Service (41) 修改云服务IIS托管管道模式为4.0经典模式
<Windows Azure Platform 系列文章目录> 这是笔者在之前的项目中遇到的问题,做一下总结,给网友做参考. 在一般情况下,Visual Studio开发的Cloud Se ...
- Java实现过滤中文乱码
最近在日志数据清洗时遇到中文乱码,如果只要有非中文字符就将该字符串过滤掉,这种方法虽简单但并不可取,因为比如像Xperia™主題.天天四川麻将Ⅱ这样的字符串也会被过滤掉. 1. Unicode编码 U ...
- Pig + Ansj 统计中文文本词频
最近特别喜欢用Pig,拥有能满足大部分需求的内置函数(built-in functions),支持自定义函数(user defined functions, UDF),能load 纯文本.avro等格 ...