套接字:为啥阻塞 read() 会因 ENOTCONN 而失败?
Posted
技术标签:
【中文标题】套接字:为啥阻塞 read() 会因 ENOTCONN 而失败?【英文标题】:Sockets: Why does a blocking read() fail with ENOTCONN?套接字:为什么阻塞 read() 会因 ENOTCONN 而失败? 【发布时间】:2011-05-16 13:41:06 【问题描述】:我正在尝试从阻塞套接字读取,但我想知道 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)
.
但同时客户端并没有关闭连接(由write()
之后的很长的sleep()
保证)
【问题讨论】:
man read
并阅读 errno
以确定发生的错误,不一定按此顺序。
【参考方案1】:
你期待什么?你说你有一个非阻塞套接字,所以它当然不会阻塞。 read
上的非阻塞套接字的行为是,如果数据可供读取,则立即返回一些数据(可能比请求的数量短),并在 errno
设置为 EAGAIN
或 @ 时返回 -1 987654324@ 如果没有可用数据。
如果您不想要非阻塞行为,为什么将套接字设置为非阻塞?
编辑: Grr,你改变了你的问题。 ENOTCONN
的原因是您试图从未连接的套接字中读取。除非通过accept
或socketpair
获得套接字,否则您必须在其上调用connect
将其连接到远程地址,然后read
才能工作。
【讨论】:
【参考方案2】:这意味着要么发生了超时,要么可能是信号中断了读取。您可以在errno.h
中使用errno
的结果来查看错误是什么,如果您希望错误采用人类可读的格式,您可以使用strerror()
或perror()
来自string.h
或@ 987654327@
更新:根据 POSIX 规范,您应该将 struct timeval
(在 sys/time.h
中定义)设置为所需的秒数和微秒数,然后超时发生到 setsockopt
当指定SO_RCVTIMEO
标志而不是将int
转换为const char*
时。因此,即使您的客户端现在可能行为不端并导致不同的错误,如果您向函数发送错误的参数类型,您仍然可能会遇到更进一步的问题。
【讨论】:
谢谢。原因是连接已经被客户端关闭(因为意外的客户端行为,见***.com/questions/6018974/…) 修复客户端后,同样的错误又回来了。我已经更新了问题。 好的,我已经为我的答案添加了更新,希望对您有所帮助。 如果上面更新的答案没有帮助,如果您在没有O_NOBLOCK
设置或任何超时的情况下在套接字上使用默认配置会发生什么? read()
是否仍会立即返回?
是的,行为是一样的。【参考方案3】:
原因在于errno。可能的情况:
[ECONNRESET]
d 参数指的是一个套接字,而远程
套接字端被强制关闭。
[EAGAIN]
文件被标记为非阻塞 I/O,并且没有数据
可以阅读了。
基本上,您可以使用以下方法进行非阻塞阻塞:
do
read(...);
while(errno == EAGAIN);
【讨论】:
【参考方案4】:超时时返回-1。
不要设置超时,它会永远阻塞(好吧,至少在套接字仍然连接时,无论如何)。
【讨论】:
超时设置为 30 秒,但似乎立即返回( 【参考方案5】:我已经解决了这个问题。 谢谢你们所有的cmets,他们帮了很大的忙。
问题在于使用了错误的文件描述符。
我将服务器套接字的文件描述符传递给read()
,而不是accept()
返回的客户端套接字的文件描述符。
【讨论】:
很高兴你发现了问题:-) 那么你可以接受告诉你检查errno
的答案之一,或者任何帮助你解决问题的方法。【参考方案6】:
read()
可能会阻塞,因此如果没有可用数据,它将返回-1
并将errno
设置为EAGAIN
或EWOULDBLOCK
。
如果您想使用read()
,您可以使用select()
或poll()
等待套接字上的数据可用。
【讨论】:
这是错误的。在阻塞模式下, read() 不会返回 EAGAIN (除非达到(可选)超时)。您正在描述非阻塞读取。以上是关于套接字:为啥阻塞 read() 会因 ENOTCONN 而失败?的主要内容,如果未能解决你的问题,请参考以下文章
如何在非阻塞套接字上处理 OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE
网络I/O模型--04非阻塞模式(解除accept() read()方法阻塞)的基础上加入多线程技术