当我打开O_NONBLOCK时,我得到;0“;及;I/O错误“;

当我打开O_NONBLOCK时,我得到;0“;及;I/O错误“;,c,linux,tcp,redhat,C,Linux,Tcp,Redhat,当我打开O_NONBLOCK时,我的连接len返回0,我的errno返回EIO。我希望len是-1,errno是EAGAIN。根据我得到的信息,我可以假设初始连接存在问题。我不明白的是为什么我会得到它。如果我在打开O_NONBLOCK的地方注释掉,我根本就没有这个问题。我是否错过了一些关于打开O_NONBLCOK的内容 我的代码(MAIN()) 编辑 也许我第一次没有说清楚,我知道errno和len与s_recv 我的问题是,当我打开O_NONBLOCK时,我得到了不想要的结果s_recv的错误

当我打开
O_NONBLOCK
时,我的连接len返回
0
,我的errno返回
EIO
。我希望len是
-1
,errno是
EAGAIN
。根据我得到的信息,我可以假设初始连接存在问题。我不明白的是为什么我会得到它。如果我在打开
O_NONBLOCK
的地方注释掉,我根本就没有这个问题。我是否错过了一些关于打开
O_NONBLCOK
的内容

我的代码(MAIN())

编辑

也许我第一次没有说清楚,我知道errno和len与
s_recv
我的问题是,当我打开O_NONBLOCK时,我得到了不想要的结果
s_recv
的错误号是EIO及其 莱恩是0。如果我关闭关闭
O_NONBLOCK
,那么我所有的问题都会消失;len为1或更多,而errno不为 需要检查

以下是我预期的情景示例:

在第一个坏的场景中,
s_recv
的Len为0或-1,errno不是EAGAIN,连接被重置

在第二场比赛中,赛昂里奥的伦比是-1,厄尔诺是伊根。这是在什么时候的示例场景 O_NONBLOCK根据手册页打开


在良好的sceanrio
s_recv
中,len大于1,无需检查errno

在下次读取之前,对
O_NONBLOCK
的更改不相关

因此,在调用
fcntl
之前,必须先检查
len
errno
。当然,您必须检查
fcntl
的返回值,因为它也可能失败

总之,
len==0
errno==EIO
与更改为
O\u NONBLOCK
无关,而是与之前的
s\u recv
有关

此外,请注意您的

if (len == -1 || len == 0 && errno != EAGAIN)

if (len == -1 || (len == 0 && errno != EAGAIN) )
这没有意义,因为如果返回值不是
-1
,则必须忽略errno。如果返回值为
0
,则对等方已关闭连接

更新

我构建了一个简单的echo客户端

fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
    error("socket");

he = gethostbyname("localhost");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ((struct in_addr*)he->h_addr)->s_addr;
addr.sin_port = htons(7); /* echo */
if (connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1)
    error("connect");

while (fgets(buf, sizeof(buf), stdin)) {
    n = strlen(buf);
    printf("fgets=%d, %s", n, buf);
    if (send(fd, buf, n, 0) == -1)
        error("send");

    n = recv(fd, buf, sizeof(buf), 0);
    if (n == -1)
        error("recv");

    printf("recv=%d, %s", n, buf);

    flags = fcntl(fd, F_GETFL, 0);
    printf("flags=%d\n", flags);
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
        error("fcntl");
}
设置
O_NONBLOCK
后,我收到

errno=11
recv:资源暂时不可用

如果我在循环之前移动
fcntl(O_NONBLOCK)
,一切正常


因此,在读取或写入套接字后不建议使用非阻塞。

问题在于线路:

if (len == -1  ||  len == 0 && errno != EAGAIN)
这相当于

if (len == -1  ||  (len == 0 && errno != EAGAIN))
因此,如果没有可用的数据(
len==-1
),您将不会选中
errno
,只会无条件地标记错误并退出。此外,当存在EOF(
len==0
)时,不会设置errno,因此检查它将给出以前调用中发生的任何情况

您可能想要:

if ((len < 0 && errnor != EGAIN) || len == 0) {
    ReceiveError = (len < 0) ? errno : 0;
if((len<0&&errnor!=EGAIN)| len==0){
ReceiveError=(len<0)?错误号:0;

此外,如果fcntl出现错误,则会出现错误errno(尽管我预计不会发生这种情况——使用GETFL/SETFL可能看到的唯一失败是EBADF)您可能想在recv调用之前进行fcntl调用。

为什么在读取后设置
O_NONBLOCK
?如果是非阻塞套接字,最好使用
选择
/
poll
。为什么在循环中和在s_recv之后进行fcntl调用?为什么您认为fcntl不能在s_recv之后更改错误号?Eddy_EM:我最初设置了O_Non为调试目的阅读后阻塞。我计划将所有内容移动到正在进行初始连接的函数。oleg_g:这是一个快速实现,用于执行一些快速调试。我理解您的观点,它应该设置在
while
循环之外。我确信我理解您的第二个问题…我不想改变错误o、 只是检查一下。“当我打开o_NONBLOCK时,我的连接len返回0,errno返回EIO。”1.当recv()时返回零,对等方已关闭连接。2.errno的值不相关,除非返回了-1。请阅读“手册”页。这不是一个真正的问题。也许我第一次没有正确解释这一点,我理解len和errno与
s_recv
有关。我的问题是,当我打开
O_NONBLOCK
My
s_rec时v
给了我不想要的结果;len是0,errno是EIO。如果我注释掉代码,打开
O_NONBLOCK
一切正常。例如:在第一个好场景中,我的
s_recv
len是1或更多,不需要检查errno。在第二个好场景中,我的
s_recv
len是-1(基于O_非块)在糟糕的情况下,如果连接中断或发生其他情况,lenis@WorkerBee如果
len==0
,您必须忽略
errno
,因为
errno
仅在
len==1
时设置。如果您得到
len==0
,则表示EOF。我相应地更新了我的答案。Olaf dietsche-Ok,应该
s\u recv
如果启用了
O_NONBLOCK
,则返回0?我询问的原因是如果我对打开
O_NONBLOCK
的位置进行注释,则我不会遇到任何问题。@WorkerBee这应该是无关的,但我没有在
读取
后设置
O_NONBLOCK
的经验。
if ((len < 0 && errnor != EGAIN) || len == 0) {
    ReceiveError = (len < 0) ? errno : 0;