In every example and discussion I run across in the context of BSD socket programming, it seems that the recommended way to set a file descriptor to nonblocking I/O mode is using the O_NONBLOCK flag to fcntl(), e.g.

int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

I've been doing network programming in UNIX for over ten years, and have always used the FIONBIO ioctl() call to do this:

int opt = 1;
ioctl(fd, FIONBIO, &opt);

Never really gave much thought to why. Just learned it that way.

Does anyone have any commentary on the possible respective merits of one or the other? I imagine the portability locus differs somewhat, but do not know to what extent as ioctl_list(2) doesn't speak to that aspect of individual ioctl methods.

推荐答案

Prior to standardization there was ioctl(...FIONBIO...) and fcntl(...O_NDELAY...), but these behaved inconsistently between systems, and even within the same system. For example, it was common for FIONBIO to work on sockets and O_NDELAY to work on ttys, with a lot of inconsistency for things like pipes, fifos, and devices. And if you didn't know what kind of file descriptor you had, you'd have to set both to be sure. But in addition, a non-blocking read with no data available was also indicated inconsistently; depending on the OS and the type of file descriptor the read may return 0, or -1 with errno EAGAIN, or -1 with errno EWOULDBLOCK. Even today, setting FIONBIO or O_NDELAY on Solaris causes a read with no data to return 0 on a tty or pipe, or -1 with errno EAGAIN on a socket. However 0 is ambiguous since it is also returned for EOF.

POSIX addressed this with the introduction of O_NONBLOCK, which has standardized behavior across different systems and file descriptor types. Because existing systems usually want to avoid any changes to behavior which might break backward compatibility, POSIX defined a new flag rather than mandating specific behavior for one of the others. Some systems like Linux treat all 3 the same, and also define EAGAIN and EWOULDBLOCK to the same value, but systems wishing to maintain some other legacy behavior for backward compatibility can do so when the older mechanisms are used.

New programs should use fcntl(...O_NONBLOCK...), as standardized by POSIX.

C++相关问答推荐

是否可以在C中进行D3 D12申请?

为什么getchar()挂起了,尽管poll()返回了一个好的值?""

POSIX文件描述符位置

GCC不警告隐式指针到整数转换'

在C中使用动态内存分配找到最小的负数

如何在c++中包装返回空*的函数

在C语言中,是否可以使枚举数向后计数?

错误:包含文件时类型名称未知

将 struct 传递给函数

为什么memcpy进入缓冲区和指向缓冲区的指针工作相同?

函数的限制限定指针参数允许优化调用方函数吗?

如何在GET_STRING输入后对少数几个特定字符串进行C判断?

为什么这个分配做得不好呢?

为什么WcrTomb只支持ASCII?

如何在C中用bool进行文件I/O?

使用C++中的字符串初始化 struct 时,从‘char*’初始化‘char’使指针变为整数,而不进行强制转换

如何在不更改格式说明符的情况下同时支持双精度和长双精度?

从整型转换为浮点型可能会改变其值.

如何在Rust中处理C的longjmp情况?

SSE 向量与 Epsilon 的比较