I/O复用select
使用多进程服务器端,创建进程时需要付出极大的代价,需要大量的运算和内存空间,每个进程都是有独立的内存空间的,所以会愈加复杂,所以I/O复用可以改善这个问题。
I/O复用的使用情形
- 客户端程序要同时处理多个socket,如我们的非阻塞技术的实现
- 客户端程序要同时处理用户的输入和网络连接。
- TCP服务器要同时处理监听socket和连接socket。
对应实现
步骤一:
设置文件描述符 |
---|
指定监视范围 |
设置超时 |
步骤二:
调用select函数 |
---|
步骤三:
查看调用结果 |
---|
设置文件描述符
使用fd_set数组变量
fd0 | fd1 | fd2 | fd3 | … |
---|---|---|---|---|
0 | 1 | 0 | 0 | … |
- FD_ZERO(fd_set * fdset) :将fd_set变量的所有位初始化为0.
- FD_SET(int fd,fd_set * fdset) : 在参数fdset指向的变量中注册文件描述符fd的信息。
- FD_CLR(int fd,fd_set * fdset) : 从参数fdset指向的变量中清楚清除文件描述符fd的信息
- FD_ISSET(int fd,fd_set * fdset) : 若参数fdset指向的变量中包含文件描述符fd的信息,则返回真
设置检查(监视)范围及时长
int select(
int maxfd, fd_set * readset, fd_set * writeset, fd_set * exceptset, const struct timeval * timeout);
- maxfd 监视对象文件描述符数量。
- readset 将所有关注“是否存在待读取数据”的文件描述符注册到fd_set型变量,并传递其地址值
- writeset 将所有关注“是否可传输无阻塞数据数据”的文件描述符注册到fd_set型变量,并传递其地址值
- exceptset 将所有关注“是否发生异常”的文件描述符注册到fd_set型变量,并传递其地址值。
- timeout 调用select函数后,为防止返回时返回0。因发生关注的事件返回时,返回大于0的值,该值是发生事件的文件描述符数。
- 返回值 发生错误时返回-1,超时时返回0,因发生关注的事情返回时,返回大于0的值,该值是发生事件的文件描述符数。
文件描述符的监视(检查)范围:文件描述符的监视范围与select函数的第一个参数有关。传值的话只需将最大的文件描述符值加1再传递到select函数即可。
select函数的超时时间与select函数的最后一个参数有关,其中timeval结构体定义如下。
struct timeval
{
long tv_sec; //秒
long tv_usec; //毫秒
}