我们所使用的I/O模型一共有五种。

分别为阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O,异步I/O。

所谓I/O复用就是指管理多个I/O文件描述符,一般会使用(select,poll,epoll)3个函数中的一个来实现I/O复用。

下面就介绍一下其中的select

int select(int nfds, fd_set *readfds, fd_set *writefds,

fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);

int  FD_ISSET(int fd, fd_set *set);

void FD_SET(int fd, fd_set *set);

void FD_ZERO(fd_set *set);

select的5个参数:

第一个参数是当前管理的所有文件描述符的最大值加1

因为在select中采用的是轮询的机制,输入参数是不包含的。

你可以这样理解:   for(fd = 0; fd<maxfd+1 ; fd++)

[顺带一提: 文件描述符0是stdin,1是stdout,2是stderr]

第二个参数是读集合

你要管理哪些文件描述符的读的事件,就把它放到fd_set *readfds结构体中(用FD_SET()函数);

第三个参数是写集合

同样,要管理哪些文件描述符的写的事件,就把它放到fd_set *readfds结构体中(用FD_SET()函数);

第四个参数是异常集合

就是监视异常事件的发生

第五个参数是超时时间的设置

struct timeval {

long tv_sec; 秒

long tv_usec; 毫毛
}

不要忽略这也是一个输入输出参数(即该参数会被函数改变),如果是一个循环,那么每次都要重新赋值该参数。

注意:select中除了第一个参数都是输入输出参数,即放在这几个位置的值都会被改变

读,写,异常集合输入参数是要监视的集合,使用完select后会变成有事件发生的事件集合,而timeout会被select函数减少

第1个参数必须设置正确(在window系统中可以不设置,但在linux系统中必须设置)

第2,3,4个参数若设置为NULL,表示不关心任何事件,若不关心其中的一种事件,可将其设置为NULL。

顺带提一下[int fileno(FILE *stream);],这个函数可以用来取得参数stream指定的文件流所使用的文件描述符。

用select函数实现并发服务器并发数量受两方面限制

1.最大文件描述符(系统参数)

可在LINUX终端直接输入 ulimit -n 查看,用 ulimit -n [数值] 改变参数

或者在程序中用setrlimit 函数改变(注意:setrlimit 函数只能改变当前进程的最大文件描述符)

2.select中的fd_set集合容量FD_SETSIZE,不容易改变,需要重新编译内核

下面是select实现的(可实现多个客户端连接)回射服务器代码

 #include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h> void myerr(char *m)
{
perror(m);
exit();
} int count = ;
int main()
{
int listenfd;
if((listenfd = socket(AF_INET, SOCK_STREAM, )) < )
myerr("socket error"); int on = ;
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < )
myerr("setsockopt error"); struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_port = htons();
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < )
myerr("bind error"); if(listen(listenfd, SOMAXCONN) < )
myerr("listen error"); int i, maxi=, conn, ret, maxfd, nready;
char recvbuf[] = "";
struct sockaddr_in peeraddr;
int connfd[FD_SETSIZE];
for(i=; i<FD_SETSIZE; i++)
connfd[i] = -;
socklen_t peerlen = sizeof(peeraddr); maxfd = listenfd;
fd_set allset, rset;
FD_ZERO(&allset);
FD_ZERO(&rset);
FD_SET(listenfd, &allset); for(;;)
{
rset = allset;
sleep();
nready = select(maxfd+, &rset, NULL, NULL, NULL);
if(nready == -)
{
if(errno == EINTR)
continue;
myerr("select");
}
if(FD_ISSET(listenfd, &rset))
{
if((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < )
myerr("accept error");
for(i=; i<FD_SETSIZE; i++)
{
if(connfd[i] == -)
{
connfd[i] = conn;
if(i > maxi)
maxi = i;
break;
}
}
// count++;
// printf("%d\n", count);
if(i == FD_SETSIZE)
{
fprintf(stderr, "too many clients\n");
exit();
}
printf("ip: %s port: %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
FD_SET(conn, &allset);
if(conn > maxfd)
maxfd = conn;
if(--nready <= )
continue;
}
for(i=; i<=maxi; i++)
{
if(connfd[i] == -)
continue;
conn = connfd[i]; if(FD_ISSET(conn, &rset))
{
memset(recvbuf, , sizeof(recvbuf));
ret = read(conn, recvbuf, sizeof(recvbuf));
if(ret == )
{
printf("client close\n");
close(conn);
connfd[i] = -;
while(connfd[maxi] == -)
{
maxi --;
if(maxi == )
break;
}
FD_CLR(conn, &allset);
continue;
}
write(conn, recvbuf, ret);
fputs(recvbuf, stdout);
if(--nready <= )
break;
}
}
}
close(listenfd);
return ;
}

select函数的介绍和使用的更多相关文章

  1. 一.Select 函数详细介绍【转】

    转自:http://www.cnblogs.com/hjslovewcl/archive/2011/03/16/2314330.html Select在Socket编程中还是比较重要的,可是对于初学S ...

  2. Linux下select函数的使用

    一.Select 函数详细介绍 Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect. accept.recv ...

  3. linux select函数详解

    linux select函数详解 在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核: •我们所关心的文件描述符 •对每个描述符,我们所关心的状 ...

  4. UNIX网络编程读书笔记:select函数

    select函数概况: select函数允许进程指示内核等待多个事件中的任何一个发生,并仅在有一个或多个事件发生或经历一段指定的时间后才唤醒它. 作为一个例子,我们可以调用select,告知内核仅在下 ...

  5. linux select函数:Linux下select函数的使用详解【转】

    本文转载自;http://www.bkjia.com/article/28216.html Linux下select函数的使用 Linux下select函数的使用 一.Select 函数详细介绍 Se ...

  6. Linux驱动 - select函数介绍

    一.select 函数介绍 select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型:          #include & ...

  7. select函数及fd_set介绍

    1. select函数 1. 用途 在编程的过程中,经常会遇到许多阻塞的函数,好像read和网络编程时使用的recv, recvfrom函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直阻塞在 ...

  8. (十二)select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

    select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型:int select(int maxfd,fd_set *rdset ...

  9. select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

    http://hi.baidu.com/%B1%D5%C4%BF%B3%C9%B7%F0/blog/item/e7284ef16bcec3c70a46e05e.html select函数用于在非阻塞中 ...

随机推荐

  1. vue.js 与iview官网

    vue.js https://cn.vuejs.org/v2/guide/instance.html#生命周期图示 iview https://www.iviewui.com/components/t ...

  2. 使用FFMPeg对视频进行处理

    FFMPeg处理视频的核心操作方式是命令,无论是在Windows上还是Linux上.那么下边就简单介绍下,常见的处理命令. 示例1:截取一张352×240尺寸大小的,格式为jpg的图片: ffmpeg ...

  3. 了解一下Http常见状态码、Http协议的工作特点和原理、Http请求Post与Get的区别

    HTTP协议常见状态码状态码的作用负责标记客户端请求服务器的返回结果,标记服务器端的处理是否正常,通知出现的错误等等职责,借助客户端可以知道客户端是否正常请求服务端.五大类:1XX(信息类状态码,接收 ...

  4. 修长城 (区间DP)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 大家都知道,长城在自然条件下会被侵蚀,因此,我们需要修复.现在是21世纪,修复长城的事情当 ...

  5. 记录一个 spring cloud 配置中心的坑,命令行端口参数无效,被覆盖,编码集问题无法读取文件等.

    spring cloud 配置中心 结合GIT , 可以运行时更新配置文件.发送指令让应用重新读取配置文件. 最近在测试服务器实现了一套,结果CPU 实用率暴增,使用docker compose启动 ...

  6. Pymongo一些常见需求(陆续补充)

    总结一下最近包括之前遇到的一些pymongo操作的问题. #需求1: 搜索文档数组里边是否存在某元素 数据: data1 = { '_id': xxxxxxxxxxxxxx, 'dataList': ...

  7. Redis笔记1-redis的搭建和使用

    1.   Redis的安装 1.1. Redis的安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: ...

  8. 关于VS2013调试IIS应用源代码时无法进入断点的问题总结

    调试无法进入断点 前言:今天再次遇到之前调试无法进入断点的问题,本来想不写呢觉得没什么只是又犯了同样的错误,但是我发现这个问题我分析起来还是挺费劲的,我仔细想了想原因, 是因为自己对之前的错误没有进行 ...

  9. Ubuntu 11.10下GRUB 2 1.99版编译安装笔记

    Ubuntu 11.10下GRUB 2 1.99版编译安装笔记 以下的安装笔记,都是QLi自己学习grub2 时,所整理的,还是新手,有错误的话,请大家帮忙就别提出来了. 最新版grub V1.99官 ...

  10. SAS 9.4 的sid问题解决方案汇总(头疼...)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 因为经常出现sid出现问题,所以问题很多.最常 ...