阻塞IO与非阻塞IO
阻塞IO
默认情况下,Linux系统上的所有文件描述符都以阻塞模式开始。 这意味着I / O系统调用如读取,写入或连接可能会阻塞。
如果你在stdin上调用read,那么你的程序将被阻塞,直到数据实际可用,例如当用户实际上在他们的键盘上物理键入字符时。具体来说,内核会将进程置于“睡眠”状态,直到数据在stdin上可用。
网络传输中,如果你尝试从TCP套接字读取,则读取调用将阻塞,直到连接的另一端实际发送数据。这种网络设置在高并发环境下就是灾难,因为只要达到阻塞的上限,那么剩下请求则没法处理。
非阻塞IO
非阻塞IO在没有数据处理的情况下直接返回且errno = 11。errno 在errno.h的定义如下:
#define EAGAIN 11 /* Try again */
设置非阻塞IO的方式
1使用fcntl在文件描述符上设置O_NONBLOCK
/*STDIN_FILENO 开启非阻塞模式 */
int flags = fcntl(STDIN_FILENO,F_GETFL,0);
fcntl(STDIN_FILENO,F_SETFL,flags | O_NONBLOCK );
/*STDIN_FILENO 开启非阻塞模式 */
/* STDIN_FILENO 关闭非阻塞模式*/
flags = fcntl(STDIN_FILENO,F_GETFL,0);
fcntl(STDIN_FILENO,F_SETFL,flags & (~O_NONBLOCK) );
2使用open函数,其中flags项包括O_NONBLOCK。
/*open函数设置描述符,开启非阻塞模式 */
int fd =open("test",O_RDWR|O_CREAT|O_NONBLOCK);
测试代码
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <unistd.h>
char buf[500000];
int
main(void)
{
int ntowrite, nwrite;
char *ptr;
/*STDIN_FILENO 开启非阻塞模式 */
int flags = fcntl(STDIN_FILENO,F_GETFL,0);
fcntl(STDIN_FILENO,F_SETFL,flags | O_NONBLOCK );
/*STDIN_FILENO 开启非阻塞模式 */
/*从STDIN_FILENO读取数据,如果是非阻塞模式,没读到数据则立刻返回 */
ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
fprintf(stderr, "read %d bytes\n", ntowrite);
/*open函数设置描述符,开启非阻塞模式 */
int fd =open("test",O_RDWR|O_CREAT|O_NONBLOCK);
ptr = buf;
while (ntowrite > 0) {
errno = 0;
nwrite = write(fd, ptr, ntowrite);
fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);
if (nwrite > 0) {
ptr += nwrite;
ntowrite -= nwrite;
}
}
/* STDIN_FILENO 关闭非阻塞模式*/
flags = fcntl(STDIN_FILENO,F_GETFL,0);
fcntl(STDIN_FILENO,F_SETFL,flags & (~O_NONBLOCK) );
close(fd);
exit(0);
}
参考链接
[1]. https://www.mkssoftware.com/docs/man5/stdio.5.asp
[2]. http://www.virtsync.com/c-error-codes-include-errno