Sockets 有人能给我一个关于';发送';非阻塞套接字的行为?

Sockets 有人能给我一个关于';发送';非阻塞套接字的行为?,sockets,send,nonblocking,berkeley-sockets,Sockets,Send,Nonblocking,Berkeley Sockets,我现在已经阅读了文档至少10次,还阅读了大约10段代码片段和完整的程序,其中使用非阻塞套接字发送数据。问题是,有些教程要么是针对初学者(Beejs f.i.)的,要么在假设方面相当草率;那些不复杂的是专门的代码示例,它们不能解释为什么要这样做。即使如此,在我看来,知识库并没有完全涵盖send行为的所有方面。我想要的是关于f.e.的细节: 返回代码0确切地表示了什么,是否值得检查errno,还是应该在不进行进一步调查的情况下放弃连接 获取负返回值是否意味着需要关闭坏掉的连接,或者只有当errno

我现在已经阅读了文档至少10次,还阅读了大约10段代码片段和完整的程序,其中使用非阻塞套接字发送数据。问题是,有些教程要么是针对初学者(Beejs f.i.)的,要么在假设方面相当草率;那些不复杂的是专门的代码示例,它们不能解释为什么要这样做。即使如此,在我看来,知识库并没有完全涵盖
send
行为的所有方面。我想要的是关于f.e.的细节:

  • 返回代码0确切地表示了什么,是否值得检查
    errno
    ,还是应该在不进行进一步调查的情况下放弃连接
  • 获取负返回值是否意味着需要关闭坏掉的连接,或者只有当
    errno
    ewoodblock
    EAGAIN
    EINTR
    (…其他)时才会这样做
  • 当返回值为
    >0
    时,是否值得检查
    errno
    ?显然,该值表示“发送”的数据量(用引号括起来,因为这确实是一个很长的过程,对不对),但由于套接字是非阻塞的,这是否意味着可以立即发出另一个调用,或者,根据
    errno
    再次,应该等待下一个发送时机(使用select/poll/epoll)
  • 基本上,是否先检查返回值,然后才检查
    errno
    值?或者可能
    send
    在每次调用时设置
    errno
    ,不管返回值如何?这将使错误检查更加容易
  • 如果一个程序获得了
    EINTR
    ,那么一个程序应该采取什么好的、健壮的行为呢?只需记录状态并在下次发送时重试,如使用
    eWoldBlock
    EAGAIN
  • 是否同时检查
    eWoldBlock
    EAGAIN
    ?我们可以相信两者具有相同的价值,还是取决于实现
  • 对于流套接字,
    send
    是否返回
    EMSGSIZE
    ?如果没有,那么缓冲区大小就太大了,对吗
  • 返回值本身是否可以等于任何一个已知错误代码

如果您能提供一个健壮的非阻塞发送代码示例,我们将不胜感激。

这里有很多问题:

  • 返回代码0确切地指示了什么,是否值得检查errno,还是应该在不进行进一步调查的情况下放弃连接
在POSIX系统上,除非使用长度arg 0调用send(2),否则send(2)永远不能返回0。检查特定系统的文档,确保其符合POSIX规范

  • 获得负的返回值是否意味着需要关闭一个坏掉的连接,或者只是这样,除非errno是ewoldblock、EAGAIN或EINTR(…其他)
否,-1返回值(唯一可能的负返回值)仅表示未发送数据。您需要检查errno以了解原因——请参阅send(2)手册页以获取所有可能的errno值及其含义的完整列表

  • 当返回值大于0时,是否值得检查errno?显然,该值表示“发送”的数据量(在引号中,因为这是一个很长的过程,对不对),但由于套接字是非阻塞的,这是否意味着可以立即发出另一个调用,或者,根据errno的不同,应该等待下一个发送时机(使用select/poll/epoll)
如果send返回success(>0),则errno将保持不变,并将包含它以前拥有的内容(这可能是某个早期系统调用的错误)

  • 基本上,是否先检查返回值,然后才检查errno值?或者在每次调用时发送设置errno,不管返回值如何?这将使错误检查更加容易
首先检查返回值,如果返回值为-1,则检查errno。如果确实需要,可以在调用之前将errno设置为0,然后在调用之后进行检查

  • 如果一个人获得了EINTR,那么对于一个程序来说,什么是好的、健壮的行为呢?只需记录状态并在下一次发送时重试,如使用eWoldBlock和EAGAIN
最简单的方法是禁用系统调用的中断,在这种情况下,您将永远无法获得EINTR。将其与EWOULDBLOCK/EAGAIN一样处理也很好

  • 有人检查EWOULDBLOCK和EAGAIN吗?我们可以相信两者具有相同的价值,还是取决于实现
取决于实现,尽管它们通常是相同的。有时,SysV与BSD仿真模式之间存在着一些奇怪之处,这可能会使它们有所不同,并且两者都可能发生

  • 发送是否返回流套接字的EMSGSIZE?如果没有,那么缓冲区大小就太大了,对吗
流套接字没有原子消息,EMSGSIZE仅用于原子消息,因此流套接字不能返回EMSGSIZE

  • 返回值本身是否可以等于任何一个已知错误代码

唯一的错误代码是-1。成功是写入的字节数,因此如果您可以在32位机器上写入2^32-1字节(或在64位机器上写入2^64-1字节),这将是一个问题,但您不能写入那么多字节(如果您尝试,通常会得到一个EINVAL或EFAULT)。

我将尝试回答您的问题

  • send
    的返回值为0表示发送了0个字节。返回值-1表示错误。如果调用长度为0的
    send
    ,则应返回0。虽然非阻塞套接字应该返回-1,如果它将阻塞,则返回的errno为EAGAIN或eWoldBlock,但如果某些实现返回的是0字节,我不会感到太惊讶
  • EWOULDBLOCK、EAGAIN和EINTR是