Linux系统编程 44 阻塞和非阻塞
学习笔记
了解概念
跟他相关的是read和write函数。
如果读的是常规的文件,不会涉及到阻塞和非阻塞。
1.设备文件
2.网络文件
/dev/tty --- 终端文件
$cat block_readtty.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char buf[10];
int n;
n = read(STDIN_FILENO,buf,10);
if( -1 == n )
{
perror("read STDIN_FILENO\n");
exit(1);
}
write(STDOUT_FILENO,buf,n);
return 0;
}
$./block_readtty
song
song
在UNIX一些系统调用中使用到STDIN_FILENO表示标准输入,STDOUT_FILENO表示标准输出,
STDERR_FILENO表示标准出错,使用时需要加头文件<unistd.h>。
当执行可执行文件的时候,没有输入的时候,就不会有$输出。
STDIN_FILENO值为0 对应标准输入- 键盘
从键盘读到buf中去。
有数据的时候,就会读走,没有数据的时候,就是阻塞。
STDOUT_FILENO 标准输出。
阻塞是谁的特性? 是read/write?
实际上不是,他是文件的属性。只不过常规文件没有这个属性
1.设备文件
2.网络文件
才有这些属性
想改变终端的属性?
O_NONBLOCK.
所以重启打开文件后,加上O_NONBLOCK参数。
read函数的返回值:
成功:读到的字节数
失败:-1,设置为errno
-1:-1 并且errno 为 EAGAIN or EWOULDBLOCK。说明不是文件读取失败,而是read以非阻塞取读取文件,且文件无数据。
EAGAIN 的头文件为 errno.h
$vim noblock_readtty.c
$cat noblock_readtty.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include<string.h>
#include<errno.h>
int main(void)
{
char buf[10];
int fd, n;
fd = open("/dev/tty",O_RDWR|O_NONBLOCK|O_NDELAY);
if(-1 == fd )
{
perror("open /dev/tty error\n");
exit(1);
}
tryagain:
n = read(STDIN_FILENO,buf,10);
if( n <= 0 )
{
printf("errno is %d",errno);
if((errno !=EAGAIN) ||(errno != EWOULDBLOCK ))
{
perror("read /dev/tty error!\n");
exit(1);
}
else
{
perror("try again\n");
write(STDOUT_FILENO,"try again\n",strlen("try again\n"));
sleep(2);
goto tryagain;
}
}
write(STDOUT_FILENO,buf,n);
close(fd);
return 0;
}
视频中
不输入的时候会提示try again
但是实际上没有,后面要在确认下原因。
实际项目开发不能这样子,不能一直占用终端。修改程序
$cat noblock_readtty_timeout.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include<string.h>
#include<errno.h>
#define MSG_TIMEOUT "TIME OUT!"
int main(void)
{
char buf[10];
int i, fd, n;
fd = open("/dev/tty",O_RDWR|O_NONBLOCK|O_NDELAY);
if(-1 == fd )
{
perror("open /dev/tty error\n");
exit(1);
}
for(i=0;i<5;i++)
{
n = read(STDIN_FILENO,buf,10);
if( n <= 0 )
{
printf("errno is %d",errno);
if((errno !=EAGAIN) ||(errno != EWOULDBLOCK ))
{
perror("read /dev/tty error!\n");
exit(1);
}
else
{
perror("try again\n");
write(STDOUT_FILENO,"try again\n",strlen("try again\n"));
sleep(2);
}
}
else
{
break;
}
}
if(5 == i)
{
write(STDOUT_FILENO,MSG_TIMEOUT,strlen(MSG_TIMEOUT));
}
else
{
write(STDOUT_FILENO,buf,n);
}
close(fd);
return 0;
}
视频的效果会输出5次try again 后显式timeout
实际上不是,原因未知!!!