文件描述符阻塞是指进程在读写文件或网络连接时,如果没有数据可读或可写,进程会一直等待,直到有数据可读或可写。这种情况下,进程会一直阻塞在读写操作上,直到数据到达或操作超时。
文件描述符非阻塞是指进程在读写文件或网络连接时,如果没有数据可读或可写,进程会立即返回,而不是一直等待。这种情况下,进程会快速返回,可以继续执行其他操作,而不会阻塞在读写操作上。
区别在于阻塞模式下,读写操作会一直等待,直到数据到达或操作超时,而非阻塞模式下,读写操作会立即返回,进程可以继续执行其他操作。阻塞模式下,进程的响应速度较慢,而非阻塞模式下,进程的响应速度较快,但需要不断地轮询文件描述符,以判断是否有数据可读或可写。
配置非阻塞模式
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
配置阻塞模式
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
在C语言中,文件描述符默认是阻塞的,从下面例子中可以观察到阻塞与非阻塞的区别
默认阻塞模式
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#define BUFFER_SIZE 32768
int rdr;
int wdr;
void WriteData()
{
int count = 0;
char data[BUFFER_SIZE] = {0};
memset(data, 1, BUFFER_SIZE - 1);
int iRet = write(wdr, data, sizeof(data));
if (iRet >= 0) {
printf("write size: %d\n", iRet);
} else {
printf("write failed, errno: %s\n", strerror(errno));
}
ioctl(wdr, FIONREAD, &count);
printf("write buf size: %d\n", count);
}
int main()
{
int maxsize = 0;
int count = 0;
int fds[2] = {-1, -1};
pipe(fds);
rdr = fds[0];
wdr = fds[1];
maxsize = fcntl(rdr, F_GETPIPE_SZ);
printf("rdr maxsize: %d\n", maxsize);
maxsize = fcntl(wdr, F_GETPIPE_SZ);
printf("wdr maxsize: %d\n", maxsize);
for (int i = 0; i < 3; i++) {
printf("begin write date, count: %d\n", i + 1);
WriteData();
printf("end write date, count: %d\n", i + 1);
}
return 0;
}
由于PIPE的缓冲区只有65536的长度,每次写入32768,前两次都可以正常写入,第三次由于缓冲区已满,写操作阻塞等待缓冲区有足够空间才能继续向下执行
配置非阻塞模式
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#define BUFFER_SIZE 32768
int rdr;
int wdr;
void WriteData()
{
int count = 0;
char data[BUFFER_SIZE] = {0};
memset(data, 1, BUFFER_SIZE - 1);
int iRet = write(wdr, data, sizeof(data));
if (iRet >= 0) {
printf("write size: %d\n", iRet);
} else {
printf("write failed, errno: %s\n", strerror(errno));
}
ioctl(wdr, FIONREAD, &count);
printf("write buf size: %d\n", count);
}
int main()
{
int maxsize = 0;
int count = 0;
int fds[2] = {-1, -1};
pipe(fds);
rdr = fds[0];
wdr = fds[1];
maxsize = fcntl(rdr, F_GETPIPE_SZ);
printf("rdr maxsize: %d\n", maxsize);
maxsize = fcntl(wdr, F_GETPIPE_SZ);
printf("wdr maxsize: %d\n", maxsize);
// 配置非阻塞模式
int flags = fcntl(wdr, F_GETFL, 0);
fcntl(wdr, F_SETFL, flags | O_NONBLOCK);
for (int i = 0; i < 3; i++) {
printf("begin write date, count: %d\n", i + 1);
WriteData();
printf("end write date, count: %d\n", i + 1);
}
return 0;
}
与上述阻塞式不同之处在于,第三次写操作时由于缓冲区已满,写函数直接退出并返回错误信息