面试题答案
一键面试以下是在Linux环境下使用C语言进行非阻塞I/O操作时可能遇到的错误及基于errno
的错误处理:
EAGAIN
或EWOULDBLOCK
:- 含义:资源暂时不可用,例如在非阻塞模式下读取套接字,而此时没有数据可读。
- 处理方式:在循环中等待一段时间后重试操作。示例代码如下:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define BUFFER_SIZE 1024
int main() {
int fd = open("test.txt", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
return 1;
}
char buffer[BUFFER_SIZE];
ssize_t bytesRead = read(fd, buffer, BUFFER_SIZE);
if (bytesRead == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 等待一段时间后重试
sleep(1);
bytesRead = read(fd, buffer, BUFFER_SIZE);
if (bytesRead == -1) {
perror("read after retry");
close(fd);
return 1;
}
} else {
perror("read");
close(fd);
return 1;
}
}
close(fd);
return 0;
}
EBADF
:- 含义:文件描述符无效。可能是因为文件描述符没有被正确打开,或者已经被关闭。
- 处理方式:检查文件描述符的获取过程,确保在使用前正确打开且未被意外关闭。例如:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main() {
int fd = -1; // 无效的文件描述符
ssize_t bytesRead = read(fd, NULL, 0);
if (bytesRead == -1) {
if (errno == EBADF) {
printf("文件描述符无效,可能未正确打开或已关闭\n");
} else {
perror("read");
}
}
return 0;
}
EINTR
:- 含义:系统调用被信号中断。例如在非阻塞I/O操作过程中,程序收到一个信号,导致操作中断。
- 处理方式:可以选择重新执行被中断的系统调用。示例如下:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define BUFFER_SIZE 1024
int main() {
int fd = open("test.txt", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
return 1;
}
char buffer[BUFFER_SIZE];
ssize_t bytesRead;
do {
bytesRead = read(fd, buffer, BUFFER_SIZE);
} while (bytesRead == -1 && errno == EINTR);
if (bytesRead == -1) {
perror("read");
close(fd);
return 1;
}
close(fd);
return 0;
}
ENOTSOCK
:- 含义:如果对非套接字的文件描述符执行了期望套接字的操作(如在非阻塞模式下对普通文件描述符进行类似套接字的I/O控制操作),会出现此错误。
- 处理方式:检查操作对象是否为正确的套接字描述符,确保操作与文件描述符类型匹配。示例:
#include <stdio.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main() {
int fd = open("test.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
perror("fcntl F_GETFL");
close(fd);
return 1;
}
// 尝试将普通文件描述符设置为非阻塞,这会导致ENOTSOCK错误
int newFlags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
if (newFlags == -1) {
if (errno == ENOTSOCK) {
printf("该操作不适用于非套接字文件描述符\n");
} else {
perror("fcntl F_SETFL");
}
}
close(fd);
return 0;
}