C 非阻塞读取管道
可以在管道上执行非阻塞I/O吗?fcntl无法设置O_非块。Linux编程接口的第918页包含一个表“从管道或FIFO(p)读取n字节的语义”。此表列出了管道和FIFO的行为,其中一列标题为O_NONBLOCK enabled?这意味着您可以在管道上设置O_NONBLOCK标志。这是正确的吗?以下代码未能设置标志,但fcntl(2)未报告错误C 非阻塞读取管道,c,linux,pipe,glibc,C,Linux,Pipe,Glibc,可以在管道上执行非阻塞I/O吗?fcntl无法设置O_非块。Linux编程接口的第918页包含一个表“从管道或FIFO(p)读取n字节的语义”。此表列出了管道和FIFO的行为,其中一列标题为O_NONBLOCK enabled?这意味着您可以在管道上设置O_NONBLOCK标志。这是正确的吗?以下代码未能设置标志,但fcntl(2)未报告错误 #include <fcntl.h> #include <sys/wait.h> #include <stdlib.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define SLEEP 1
int
main(int argc, char *argv[]) {
pid_t childPid;
int pfd[2];
int nread, flags;
int c = 'a';
setbuf(stdout, NULL);
if (pipe(pfd) == -1) {
printf("error: pipe");
exit(EXIT_FAILURE);
}
switch (childPid = fork()) {
case -1:
printf("error: fork");
exit(EXIT_FAILURE);
case 0: /* child */
if (close(pfd[0]) == -1) {
printf("child: close pfd read");
exit(EXIT_FAILURE);
}
sleep(SLEEP);
_exit(EXIT_SUCCESS);
default:
break;
/* parent falls through */
}
if (close(pfd[1]) == -1) {
printf("parent: close pipe write");
exit(EXIT_FAILURE);
}
flags = fcntl(pfd[0], F_GETFD);
flags |= O_NONBLOCK;
if (fcntl(pfd[0], F_SETFD, flags))
perror("fcntl");
/* verify flags set correctly */
flags = fcntl(pfd[0], F_GETFD);
if (!(flags & O_NONBLOCK)) {
printf("failed to set O_NONBLOCK\n");
exit(EXIT_FAILURE);
}
wait(NULL);
exit(EXIT_SUCCESS);
}
#包括
#包括
#包括
#包括
#包括
#定义睡眠1
int
main(int argc,char*argv[]){
pid_t childPid;
int-pfd[2];
国际nread,旗帜;
int c='a';
setbuf(标准输出,空);
如果(管道(pfd)=-1){
printf(“错误:管道”);
退出(退出失败);
}
开关(childPid=fork()){
案例1:
printf(“错误:fork”);
退出(退出失败);
案例0:/*儿童*/
如果(关闭(pfd[0])=-1){
printf(“子项:关闭pfd读取”);
退出(退出失败);
}
睡眠;
_退出(退出成功);
违约:
打破
/*父母破产*/
}
如果(关闭(pfd[1])=-1){
printf(“父:关闭管道写入”);
退出(退出失败);
}
标志=fcntl(pfd[0],F_GETFD);
标志|=O|U非块;
if(fcntl(pfd[0],F_设置,标志))
perror(“fcntl”);
/*验证标志设置是否正确*/
标志=fcntl(pfd[0],F_GETFD);
如果(!(标志和O_非块)){
printf(“未能设置O_非块\n”);
退出(退出失败);
}
等待(空);
退出(退出成功);
}
管道和O_非阻塞没有什么特殊之处。下面的示例按预期工作。我没有检查每个调用的每个retval,以使示例更具可读性。实际应用程序必须进行检查
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int main()
{
int fds[2];
pid_t pid;
char buf[100];
pipe(fds);
pid = fork();
if ( pid )
{
while (1 )
{
memcpy( buf, "abcdefghi\0",10);
write( fds[1], buf, 10);
sleep(2);
}
}
else
{
int retval = fcntl( fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
printf("Ret from fcntl: %d\n", retval);
while (1)
{
ssize_t r=read( fds[0], buf, 10 );
printf("read: %d\n", r);
if ( r > 0 )
{
printf("Buffer: %s\n", buf);
}
else
{
printf("Read nothing\n");
perror("Error was");
sleep(1);
}
}
}
}
请将F_SETFD
更改为F_SETFL
,并将其更改为get操作。您不会更改文件描述符标志
,而是更改文件状态标志
:-)
从man 3 fcntl
:
文件描述符标志
以下命令操作与文件关联的标志
描述符。目前,只定义了一个这样的标志:FD_CLOEXEC
关闭exec标志。如果FD_CLOEXEC位为0,则文件描述符
将在execve(2)中保持打开状态,否则它将关闭
文件状态标志
每个打开的文件描述都有特定的相关状态标志ini‐
通过open(2)初始化,并可能通过fcntl()修改。重复文件
描述符(由dup(2)、fcntl(F_DUPFD)、fork(2)等组成)指
相同的打开文件描述,因此共享相同的文件状态
旗帜
F_SETFL(内部)
将文件状态标志设置为arg指定的值。文件
访问模式(O_RDONLY、O_WRONLY、O_RDWR)和文件创建标志
arg中的(即O_CREAT、O_EXCL、O_NOCTTY、O_TRUNC)被忽略。
在Linux上,此命令只能更改O_APPEND、O_ASYNC、,
O_DIRECT、O_NOATIME和O_NONBLOCK标志。这是不可能的
更改O_数据同步和O_同步标志;请参阅下面的BUGS
它看起来像是
F_GETFD
操作中的一个bug。我已经确认,这实际上设置了描述符非阻塞,操作也不阻塞,但是F_GETFD
仍然返回零。抓好了Klaus,我感觉这是我在做的傻事。谢谢你抽出时间。
flags = fcntl(pfd[0], F_GETFD);
flags |= O_NONBLOCK;
if (fcntl(pfd[0], F_SETFD, flags))