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

发布于 2024-11-07 08:41:30 字数 955 浏览 2 评论 0原文

我正在尝试从阻塞套接字读取数据,但我想知道 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()才会真正阻塞?
  • 我可能会遇到一些陷阱吗? (我的程序中存在错误?)

我知道关于此主题还有另一个问题,但我在那里找不到我的问题的答案。

UPDATE

在不设置超时的情况下,read() 也会立即返回(主观地)-1

UPDATE 2

errno 为 107 (ENOTCONN,传输端点未连接)。 但客户端同时还没有关闭连接(通过 write() 之后长时间的 sleep() 确保)

I am trying to read from a blocking socket, but I am wondering that read() returns -1, which I think means that there's currently no data to read - I would expect that it blocks until it can read the amount of bytes.

I also tried ensuring that the socket is in blocking mode and that a high timeout is set using:

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));
}

But this hasn't changed anything.

My question:

  • What do I have to do that read() will really block?
  • Are there some pitfalls which I might hit? (bug in my program?)

I know that there's another question on this topic, but there I cannot find the answer for my question.

UPDATE

Without setting a timeout, read() also returns (subjectivly) immediately -1

UPDATE 2

errno is 107 (ENOTCONN, Transport endpoint is not connected).
But the client side has not closed the connection in the meanwhile (ensured by a long sleep() after write() )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

千と千尋 2024-11-14 08:41:30

你期望什么?你说你有一个非阻塞套接字,所以它当然不会阻塞。非阻塞套接字在读取时的行为是,如果有数据可供读取,则立即返回一些数据(可能比请求的数量短),并返回 -1 和 errno<如果没有可用数据,/code> 设置为 EAGAINEWOULDBLOCK

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

编辑: 呃,你改变了你的问题。 ENOTCONN 的原因是您试图从未连接的套接字读取数据。除非套接字是通过 acceptsocketpair 获得的,否则您必须在 read< 之前对其调用 connect 以将其连接到远程地址/code> 会起作用。

What do you expect? You said you have a non-blocking socket so of course it does not block. The behavior for a non-blocking socket on read is to immediately return with some data (possibly shorter than the requested amount) if data is available to read, and to return -1 with errno set to EAGAIN or EWOULDBLOCK if no data is available.

If you don't want non-blocking behavior, why did you set the socket to be non-blocking?

Edit: Grr, you've changed your question. The reason for ENOTCONN is that you're trying to read from a socket that is not connected. Unless a socket was obtained by accept or socketpair, you must call connect on it to connect it to a remote address before read will work.

入画浅相思 2024-11-14 08:41:30

这意味着要么超时,要么可能有信号中断读取。您可以使用 errno.h 中的 errno 的结果来查看错误是什么,如果您希望以人类可读的格式显示错误,则可以使用 <来自 string.hstdlib.h 的 code>strerror() 或 perror()

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

It means that either there was a time-out, or possibly a signal interrupted the read. You can use the results of errno in errno.h to see what the error is, and if you want the error in a human-readable formating, you can use either strerror() or perror() from string.h or stdlib.h

Update: According to the POSIX specification, you should be passing a struct timeval (defined in sys/time.h) set to the desired number of seconds and microseconds before a timeout occurs to setsockopt when specifying the SO_RCVTIMEO flag rather than casting an int to a const char*. So even though your client may be mis-behaving and causing a different error right now, you could still end up with problems further down the line if you're sending the wrong argument types to the function.

七度光 2024-11-14 08:41:30

原因就在errno中。可能的情况:

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

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

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

The reason is in errno. Likely scenarios:

  • [ECONNRESET] The d argument refers to a socket, and the remote
    socket end is forcibly closed.
  • [EAGAIN] The file was marked for non-blocking I/O, and no data
    were ready to be read.

Basically, you make non-blocking blocking using:

do
{
    read(...);
} while(errno == EAGAIN);
雨的味道风的声音 2024-11-14 08:41:30

超时时返回-1。

不要设置超时,它将永远阻塞(至少在套接字仍处于连接状态时)。

It returns -1 when it times out.

Don't set a timeout and it will block forever (Well, at least while the socket is still connected, anyway).

故人如初 2024-11-14 08:41:30

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

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

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

I've solved the problem.
Thank you for all your comments, they had been a great help.

The problem was the usage of the wrong file descriptor.

I passed the file descriptor of the server socket to read(), instead of the file descriptor of the client socket which accept() returned.

春风十里 2024-11-14 08:41:30

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

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

read() could block, so if there's no data available it will return -1 and set errno to EAGAIN or EWOULDBLOCK.

If you wand to use read(), you could use select() or poll() to wait for availability of data on the socket.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文