SO_ERROR 与 errno
Posted
技术标签:
【中文标题】SO_ERROR 与 errno【英文标题】:SO_ERROR vs. errno 【发布时间】:2014-01-28 16:22:45 【问题描述】:对于获取套接字系统调用(如recv
)错误,哪个更好(在性能级别)?
errno
或者使用SO_ERROR
作为getsockopt()
optname?
我认为errno
(在我的系统上定义为__error()
)更快,因为它不是系统调用。我说的对吗?
SO_ERROR 的优点是:获取后自动错误重置,并且我们确信错误只与我们的套接字有关。更安全。
你觉得哪个更好?两者的性能真的有区别吗?
【问题讨论】:
关于 SO_ERROR 的要点在于,即使在您调用了其他系统调用之后,它仍然安全地隐藏在套接字数据中……例如select()
,也可以设置 errno
。
【参考方案1】:
引用Dan Bernstein:
情况:您设置了一个非阻塞套接字并执行了一个返回-1/EINPROGRESS 或-1/EWOULDBLOCK 的connect()。您 select() 用于可写性的套接字。只要连接成功或失败,它就会返回。 (例外:在某些旧版本的 Ultrix 下,select() 在 75 秒超时之前不会注意到失败。)
问题:select() 返回可写性后你会做什么?连接失败了吗?如果是这样,它是如何失败的?
如果连接失败,原因会隐藏在套接字中名为 so_error 的内容中。现代系统让您可以通过 getsockopt(,,SO_ERROR,,) 查看 so_error ...
他接着讨论了getsockopt(,,SO_ERROR,,)
是一项不能在旧系统上运行的现代发明这一事实,以及如何在此类系统上获取错误代码。但是,如果您正在为过去 15 年发布的 Unix/Linux 系统编程,您可能不需要担心这一点。
connect
的 Linux 手册页描述了 SO_ERROR
的相同用法。
因此,如果您在套接字上执行异步操作,您可能需要使用SO_ERROR
。在任何其他情况下,只需使用errno
。
【讨论】:
Dan Bernstein 关于“旧版本的 Ultrix”的说法不正确。 75 秒的超时仍然存在。如果对等方主动拒绝(即响应),则 select() 会提前通知连接失败。如果根本没有响应,超时仍然适用。精确的超时时间取决于平台。 @EJP:在超时没有响应之前,没有失败。 @EJP 我相信 djb 的观点是,一些旧版本的 Ultrix 在 75 秒超时到期之前不会报告主动拒绝(例如 RST 数据包),无论拒绝何时发生。这与 Ultrix 或任何其他系统是否在 75 秒无响应后报告故障无关。 那么exceptfds
呢?微软说:msdn.microsoft.com/en-us/library/windows/desktop/…“如果套接字正在处理连接调用(非阻塞),连接尝试失败会在 exceptfds 中指示(然后应用程序必须调用 getsockopt SO_ERROR 来确定错误值)。” - 这个 exceptfds 行为是特定于 Win 的还是它也适用于 *nixes?
从历史上看,exceptfds 的唯一用途是检测 TCP 带外数据。一些系统现在是否将它用于其他事情,我不能说。【参考方案2】:
引用Unix网络编程:
如果当进程调用 read 时 so_error 非零并且没有 要返回的数据,读取返回–1,errno 设置为 so_error 的值 (TCPv2 第 516 页)。 so_error 的值然后重置为 0。如果有 是为套接字排队的数据,该数据由 read 返回 的错误情况。如果进程调用时 so_error 不为零 写入,返回 –1,并将 errno 设置为 so_error 的值(第 495 页) TCPv2) 并且 so_error 被重置为 0。
所以,errno 是更好的选择,除非您想在数据完全获取之前立即得到错误。
【讨论】:
以上是关于SO_ERROR 与 errno的主要内容,如果未能解决你的问题,请参考以下文章