套接字:为什么阻塞read()会因ENOTCONN而失败?

时间:2011-05-16 13:41:06

标签: c sockets io blocking nonblocking

我试图从阻塞套接字读取,但我想知道read()返回-1,我认为这意味着当前没有数据可读 - 我希望它会阻塞,直到它可以读取字节数。

我还尝试确保套接字处于阻塞模式,并使用以下命令设置高超时:

int setBlockingIO(int fd)
{
       int flags = fcntl(fd, F_GETFL);
       fcntl(fd, F_SETFL, flags & (~O_NONBLOCK));
       int nTimeout = 30000; // 30 seconds
       setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&nTimeout, sizeof(int));
}

但这并没有改变任何事情。

我的问题:

  • 我必须做read() really block?
  • 我可能会遇到一些陷阱吗? (我的程序中的错误?)

我知道这个主题有another question,但我无法找到问题的答案。

更新

如果没有设置超时,read()也会立即返回(主观)-1

更新2

errno是107(ENOTCONN, Transport endpoint is not connected)。 但是客户端同时没有关闭连接(在sleep()之后write()确定<{1}}

6 个答案:

答案 0 :(得分:4)

你期待什么?你说你有一个非阻塞套接字,所以它当然不会阻塞。如果数据可供读取,则read上的非阻塞套接字的行为是立即返回一些数据(可能短于请求的数量),并返回-1,errno设置为{如果没有可用数据,则{1}}或EAGAIN

如果您不想要非阻塞行为,为什么要将套接字设置为非阻塞?

编辑:格尔,你已经改变了你的问题。 EWOULDBLOCK的原因是您尝试从未连接的套接字读取。除非ENOTCONNaccept获得套接字,否则必须在其上调用socketpair才能将其连接到远程地址,然后connect才会生效。

答案 1 :(得分:3)

这意味着要么超时,要么可能是信号中断了读取。您可以在errno中使用errno.h的结果来查看错误是什么,如果您希望错误出现在人类可读的格式中,您可以使用strerror()或{{1来自perror()string.h

更新:根据POSIX规范,您应该在发生超时之前将stdlib.h(在struct timeval中定义)设置传递到所需的秒数和微秒数在指定sys/time.h标志时向setsockopt发送,而不是将SO_RCVTIMEO投射到int。因此,即使您的客户端现在可能出现错误行为并导致不同的错误,如果您向函数发送错误的参数类型,您仍然可能会遇到问题。

答案 2 :(得分:2)

原因在于errno。可能的情景:

  • [ECONNRESET] d参数指的是套接字和远程 套接字端被强行关闭。
  • [EAGAIN]文件标记为非阻塞I / O,没有数据 准备好了。

基本上,您使用以下方法进行非阻塞阻止:

do
{
    read(...);
} while(errno == EAGAIN);

答案 3 :(得分:1)

超时时返回-1。

不要设置超时,它会永远阻塞(好吧,至少在套接字仍然连接时,无论如何)。

答案 4 :(得分:0)

我已经解决了这个问题 感谢您的所有意见,他们给了我们很大的帮助。

问题在于使用错误的文件描述符

我将服务器套接字的文件描述符传递给read(),而不是accept()返回的客户端套接字的文件描述符。

答案 5 :(得分:0)

read()可能会阻止,因此如果没有可用数据,则会返回-1并将errno设置为EAGAINEWOULDBLOCK

如果您想使用read(),可以使用select()poll()等待套接字上的数据可用性。