SO_ERROR和errno的区别

11

在获取套接字系统调用(如 recv)错误时,哪种方式更好(在性能方面)?

  • 使用老旧的 errno
  • 或者作为 getsockopt() optname 使用 SO_ERROR

我认为 errno (在我的系统上定义为 __error())更快,因为它不是一个系统调用。我对吗?

SO_ERROR 的优点是:在获取后会自动重置错误,并且我们确信该错误仅涉及我们的套接字。它更安全。

你认为哪一个更好?这两者之间真的有性能差异吗?


4
关于SO_ERROR的重点在于,即使您调用了其他系统调用(例如select())并且可能会设置errno,它仍然安全地储存在套接字数据中。 - user207421
2个回答

10

引用丹·伯恩斯坦的话:

情况:您设置了一个非阻塞套接字并执行 connect(),返回 -1/EINPROGRESS 或 -1/EWOULDBLOCK。然后,您将套接字选择为可写状态。这将在连接成功或失败时立即返回。(例外情况:在某些旧版 Ultrix 中,select() 在 75 秒超时之前无法注意到连接失败。)

问题:select() 返回可写性后该怎么办?连接是否失败?如果失败了,它是如何失败的?

如果连接失败,原因会隐藏在套接字中的 something called so_error 中。现代系统可以使用 getsockopt(,,SO_ERROR,,) 查看 so_error...

他继续讨论了 getsockopt(,,SO_ERROR,,) 是一个现代发明,不适用于旧系统,并介绍了如何在这些系统上获取错误代码。但如果您正在为发布在过去15年内的Unix/Linux系统编程,那么您可能不需要担心这个问题。

Linux 的 connect 手册描述了 SO_ERROR 的同样用法。

因此,如果您在套接字上执行异步操作,则可能需要使用SO_ERROR。在任何其他情况下,只需使用errno


丹·伯恩斯坦关于“旧版本的Ultrix”是错误的。75秒超时仍然存在。如果对等方进行了主动拒绝,即响应,则select()会更早地注意到连接失败。如果根本没有响应,则超时仍然适用。精确的超时时间取决于平台。 - user207421
@EJP:只有在超时没有响应时才会出现失败。 - R.. GitHub STOP HELPING ICE
@EJP,我相信djb的观点是,一些旧版本的Ultrix在75秒超时到期之前不会报告活动拒绝(例如RST数据包),而与拒绝发生的时间无关。这与Ultrix或任何其他系统在75秒无响应后报告失败无关。 - rob mayoff
那么exceptfds呢?微软表示:https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx "如果一个套接字正在处理连接调用(非阻塞),则连接尝试失败将在exceptfds中指示(应用程序必须随后调用getsockopt SO_ERROR来确定错误值)" - 这个exceptfds行为是仅适用于Windows还是*nix系统也可以使用? - JustAMartin
历史上,exceptfds 的唯一用途是检测 TCP 带外数据。至于现在是否有些系统将其用于其他用途,我无法确定。 - rob mayoff
据我所知,Windows是唯一使用exceptfds报告非阻塞connect()失败的系统。 - Remy Lebeau

2
引用自Unix Network Programming
如果进程在调用read时,so_error非零且没有数据可返回,则read返回-1,并将errno设置为so_error的值(TCPv2的第516页)。然后将so_error的值重置为0。如果套接字上有数据排队,则read会返回该数据而不是错误条件。如果进程在调用write时,so_error非零,则返回-1,并将errno设置为so_error的值(TCPv2的第495页),然后将so_error重置为0。
因此,在完全获取数据之前,errno是更好的选择,除非您想立即获得错误信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接