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 ...
随机推荐
- SSIS package 更新 variable
在Package中声明一个variable,在package运行的过程中,SSIS如何update Variable? 第一种方法:使用 Script Task 来更新Variable的值 1,创建一 ...
- 第四章 HTML与JavaScript
DHTML就是与CSS和Web文档进行交互生成动态页面的JavaScript. 4.1HTML文档剖析 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML ...
- 【WP 8.1开发】解决调用真实摄像头会死机的问题
无论你是用Silverlight还是用RT的API来开发,在使用MediaCapture拍照片或录视频时,要是在模拟器上运行会万事大吉:但是,一旦放到真实手机上运行,肯定有人发现了,细心的朋友肯定发现 ...
- demo
NGUI demo:http://112.124.104.173/killer/demo/demo.html 网络游戏架构(服务器放在阿里云,有时连接不上可能是服务器没有开) 只是测试框架,美术都是本 ...
- 使用ExifInterface设置Datetime发生的问题
最近在弄一个Android小程序,需要把图像的生成时间设置到Exif的Datetime,用ExifInterface.setAttribute(ExifInterface.TAG_DATETIME,& ...
- UML学习总结
UML中的4+1模型 UML的4+1模型是一个叫Kruchten的人发明的,但网上还有其它版本的4+1 模型:Use case view, Logic view, Process view, Impe ...
- 在ssh中利用Solr服务建立的界面化站内搜索---solr2
继上次匆匆搭建起结合solr和nutch的所谓站内搜索引擎之后,虽当时心中兴奋不已,可是看了看百度,再只能看看我的控制台的打印出每个索引项的几行文字,哦,好像差距还是有点大…… ...
- Windows Azure Virtual Machine (32) 如何在Windows操作系统配置SFTP
<Windows Azure Platform 系列文章目录> 下载地址:http://files.cnblogs.com/files/threestone/Windows_SFTP.pd ...
- 关于HttpHandler的相关知识总结
一.关于IHttpHandler.IsReusable 很多人不明白,这哥们到底干嘛的,估计是微软最初的一个想法--让一个对象可以一直不断地被重复使用 ,但这个想法不成熟,会带来很多隐藏问题,一个对象 ...
- img[src*="same"]{}
假如你有一组图片,你想选择其中一些名字中带有same的图片,那么你就可以用这种写法,这里的意思就是选择所有正确路径下名字中带有same的图片文件. 譬如说:me_same.png,you_same.p ...