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的主要内容,如果未能解决你的问题,请参考以下文章

errno线程安全性

为啥getsockopt optlen 为零?

LDAP 与 MYSQL .. JA-SIG CAS 与 LDAP 与 CAS 与 MySQL

python网络编程基础(线程与进程并行与并发同步与异步)

=与==&与&&| 与 || 的区别

与 0 进行比较与与某个值进行比较是不是更快?