fcntl() 在打开的文件描述符 FD 上执行下面描述的操作之一。 操作由 cmd 确定。
fcntl() 可以采用可选的第三个参数。 是否需要此参数由 cmd 确定。 所需的参数类型在后面的括号中指示。
每个cmd名称(在大多数情况下,所需的类型是int,我们使用名称arg来标识参数),或者如果不需要参数,则指定void。
下图是对是否需要设置可变参数的解释:
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <cstring>
#include <cerrno>
void SetNonBlock(int fd)
{
// 提取文件描述符属性(返回值是一个位图)
int f1 = fcntl(0, F_GETFL);
if (f1 < 0)
{
perror("fcntl");
return;
}
// 使用F_SETFL将文件描述符设置回去,加上O_NONBLOCK参数。
fcntl(0, F_SETFL, f1 | O_NONBLOCK);
}
int main()
{
char buffer[1024];
SetNonBlock(0); // 设置非阻塞。
while (true)//轮询
{
sleep(1);
printf(">>> ");
fflush(stdout);
ssize_t n = read(0, buffer, sizeof(buffer) - 1); // (检查条件是否就绪)等+拷贝
if (n > 0)
{
buffer[n - 1] = 0; // 因为从标准输入读取,回车键也会放入内核缓冲区,被上层读取。
std::cout << "echo# " << buffer << std::endl;
}
else if (n == 0)
{
std::cout << "end file" << std::endl;
}
else
{
// 区分是真正出错还是数据没有就绪这两种情况。
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
// 底层数据没有就绪,希望你下次继续来检测
std::cout<<"data not ready"<<std::endl;
continue;
}
else if (errno == EINTR)
{
// 这次I/O被信号中断,也需要重新读取
continue;
}
else
{
//真正出错
std::cout << "WARNING!!! ERRNO: " << errno << ",error: " << strerror(errno) << std::endl;
break;
}
}
}
return 0;
}