【1】IO模型
1-- 阻塞式IO
最常用、最简单、效率最低
2-- 非阻塞式IO
可防止进程阻塞在I/O操作上,需要轮询,效率高,不常用。
如何将阻塞式IO 变为 非阻塞式IO?
第一种:
fd = open(pathname, O_RDONLY|O_NONBLOCK);
第二种:
位操作,寄存器操作,他们都要遵循读、改、写原则。
int fcntl(int fd, int cmd, ... /* arg */ );
功能:获取或者设置文件属性信息
参数:fd 文件描述符
cmd F_GETFL 获取文件的属性 , arg 被忽略
F_SETFL 设置文件的属性 , arg 参数必须有
返回值:成功 获取文件的属性信息
或者 为0, 取决于 cmd
出错 -1
第一步:读取信息
int flags;
flags = fcntl(fd, F_GETFL);
第二步:修改信息
flags |= O_NONBLOCK;
第三步:写信息
fcntl(fd, F_SETFL, flags);
3-- IO多路复用
允许同时对多个I/O进行控制
4-- 信号驱动IO
一种异步通信模型。
【2】IO多路复用
先构造一张有关描述符的表,然后调用一个函数。当这些文件描述符
中的一个或多个已准备好进行I/O时函数才返回。函数返回时告诉进程
那个描述符已就绪,可以进行I/O操作。
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:允许一个程序监听多个文件描述符集合,阻塞等待直到有一个
或多个文件描述符准备就绪,函数立刻返回。否则一直等待下去。
timeout 为NULL
参数:nfds 最大文件描述符加1(因为标准输入的文件描述符的值为0)
readfds 读资源文件描述符集合
writefds 写资源文件描述符集合
exceptfds 其他异常的文件描述符集合
timeout 超时时间,NULL 表示一直阻塞
返回值:成功 已经准备就绪的文件描述符的个数
出错 -1
注意点:当select 函数返回之后,内核会将没有准备就绪的文件描述符删除掉。
所以每次在监听之前,都需要重新添加监听文件描述符。
select是阻塞的,Select的好处是可以同时处理若干个Socket,如果你直接用Socket收发,你得给每一个Socket开一个线程,很浪费啊
当select执行后,会将没有活动的文件描述符删除掉,所以每次需要重新添加文件描述符
void FD_CLR(int fd, fd_set *set);
功能:将fd 从集合中 清除掉
int FD_ISSET(int fd, fd_set *set);
功能:判断fd 是否在集合中
void FD_SET(int fd, fd_set *set);
功能:将fd 添加到集合中
void FD_ZERO(fd_set *set);
功能:将集合清零
/* fd_set for select and pselect. */
typedef struct
{
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS]; // 数组
# define __FDS_BITS(set) ((set)->__fds_bits)
} fd_set;
1-- 阻塞式IO
最常用、最简单、效率最低
2-- 非阻塞式IO
可防止进程阻塞在I/O操作上,需要轮询,效率高,不常用。
如何将阻塞式IO 变为 非阻塞式IO?
第一种:
fd = open(pathname, O_RDONLY|O_NONBLOCK);
第二种:
位操作,寄存器操作,他们都要遵循读、改、写原则。
int fcntl(int fd, int cmd, ... /* arg */ );
功能:获取或者设置文件属性信息
参数:fd 文件描述符
cmd F_GETFL 获取文件的属性 , arg 被忽略
F_SETFL 设置文件的属性 , arg 参数必须有
返回值:成功 获取文件的属性信息
或者 为0, 取决于 cmd
出错 -1
第一步:读取信息
int flags;
flags = fcntl(fd, F_GETFL);
第二步:修改信息
flags |= O_NONBLOCK;
第三步:写信息
fcntl(fd, F_SETFL, flags);
3-- IO多路复用
允许同时对多个I/O进行控制
4-- 信号驱动IO
一种异步通信模型。
【2】IO多路复用
先构造一张有关描述符的表,然后调用一个函数。当这些文件描述符
中的一个或多个已准备好进行I/O时函数才返回。函数返回时告诉进程
那个描述符已就绪,可以进行I/O操作。
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:允许一个程序监听多个文件描述符集合,阻塞等待直到有一个
或多个文件描述符准备就绪,函数立刻返回。否则一直等待下去。
timeout 为NULL
参数:nfds 最大文件描述符加1(因为标准输入的文件描述符的值为0)
readfds 读资源文件描述符集合
writefds 写资源文件描述符集合
exceptfds 其他异常的文件描述符集合
timeout 超时时间,NULL 表示一直阻塞
返回值:成功 已经准备就绪的文件描述符的个数
出错 -1
注意点:当select 函数返回之后,内核会将没有准备就绪的文件描述符删除掉。
所以每次在监听之前,都需要重新添加监听文件描述符。
select是阻塞的,Select的好处是可以同时处理若干个Socket,如果你直接用Socket收发,你得给每一个Socket开一个线程,很浪费啊
当select执行后,会将没有活动的文件描述符删除掉,所以每次需要重新添加文件描述符
void FD_CLR(int fd, fd_set *set);
功能:将fd 从集合中 清除掉
int FD_ISSET(int fd, fd_set *set);
功能:判断fd 是否在集合中
void FD_SET(int fd, fd_set *set);
功能:将fd 添加到集合中
void FD_ZERO(fd_set *set);
功能:将集合清零
/* fd_set for select and pselect. */
typedef struct
{
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS]; // 数组
# define __FDS_BITS(set) ((set)->__fds_bits)
} fd_set;