我现在已经阅读了至少10次文档,并且还阅读了大约10个代码片段和完整程序,其中非阻塞套接字用于发送数据。问题是,有些教程要么适合初学者(Beejs f.i.),要么在他们的假设中非常草率;那些不复杂的是专门的代码示例,无法解释他们为什么这么做。在我看来,即使是SO知识库也没有详尽地涵盖send
行为的全部范围。我所追求的是关于f.e的详细信息:
errno
或者是否应该在没有进一步调查的情况下丢弃连接?errno
为EWOULDBLOCK
,EAGAIN
或EINTR
(...其他)?errno
时,是否值得检查> 0
?显然,该值表示“已发送”的数据量(在引号中,因为它确实是一个很长的过程,正确),但由于套接字是非阻塞的,这是否意味着可以立即发出另一个调用,或者,取决于{{ 1}}再次,应该等待下一个发送时机(使用select / poll / epoll)?errno
值吗?或者也许errno
在每次通话时设置send
,无论如何返回值?这样可以使错误检查更容易...... errno
,那么程序要采取什么样的良好,强健的行为?只需记录状态并在下次发送时重试,例如EINTR
和EWOULDBLOCK
?EAGAIN
和 EWOULDBLOCK
?我们可以信任两者具有相同的价值,还是依赖于实施?EAGAIN
是否会为流套接字返回send
?如果没有,那么没有缓冲区大小太大,对吗?如果你能提供一个强大的非阻塞发送代码的例子,那将是绝对赞赏的。
答案 0 :(得分:9)
这里有很多问题:
- 返回代码0的确切含义是什么,是否值得检查errno或者是否应该在没有进一步调查的情况下丢弃连接?
在POSIX系统上,send(2)永远不会返回0,除非你用arg为0调用它。检查你的特定系统的文档以确保它遵循POSIX规范
- 获得负回报值是否可以保证关闭连接变坏,或者只是如此,除非errno是EWOULDBLOCK,EAGAIN或EINTR(......其他)?
不,-1返回值(唯一可能的负返回值)只表示没有发送数据。你需要检查errno以查看为什么 - 请参阅send(2)手册页以获取所有可能的errno值及其含义的完整列表
- 当返回值为>时,是否值得检查错误号码0?显然,该值表示“已发送”的数据量(在引号中,因为它确实是一个很长的过程,正确),但由于套接字是非阻塞的,这是否意味着可以立即发出另一个呼叫,或者,再次依赖于errno ,应该等待下一次发送时机(使用select / poll / epoll)?
如果send返回成功(> 0),则errno将保持不变,并且将包含之前的任何内容(这可能是某些早期系统调用的错误)。
- 基本上,首先检查返回值,然后再检查errno值吗?或者也许在每次通话时发送套装errno,无论如何返回值?这样可以使错误检查更容易......
首先检查返回值,然后检查错误,如果返回值为-1。如果你真的想,你可以在通话前将errno设置为0,然后再检查
- 如果有人获得EINTR,那么程序要采取什么样的良好,强健的行为?只需记录状态并在下次发送时重试,例如EWOULDBLOCK和EAGAIN?
嗯,最简单的方法是禁用系统调用的中断,在这种情况下,你永远不会获得EINTR。像EWOULDBLOCK / EAGAIN一样处理它也很好。
- 是否检查EWOULDBLOCK和EAGAIN?我们可以信任两者具有相同的价值,还是依赖于实施?
取决于实施,但通常它们是相同的。有时SysV与BSD仿真模式之间存在奇怪之处,可能会使它们不同并且可能发生
- 是否为流套接字发送返回EMSGSIZE?如果没有,那么没有缓冲区大小太大,对吗?
流套接字没有原子消息,EMSGSIZE仅用于原子消息,所以不,流套接字不能返回EMSGSIZE
- 返回值本身是否等于任何已知的错误代码?
唯一的错误代码是-1。成功是写入的字节数,因此如果您可以在32位计算机上写入2 ^ 32-1个字节(或者在64位计算机上写入2 ^ 64-1),那么这将是一个问题,但您不能写下那么多字节(如果你尝试的话,你通常会获得EINVAL或EFAULT)。
答案 1 :(得分:3)
我会尽力回答你的问题。
send
的返回值0表示发送了0个字节。错误由返回值-1指示。如果您使用长度0调用send
,则应该返回0。虽然非阻塞套接字应返回-1,并且如果它会阻塞,则返回EAGAIN或EWOULDBLOCK的错误,如果某些实现返回写入的0字节,我不会感到惊讶。select
。errno
会告诉您没有用。select
循环。#if EAGAIN == EWOULDBLOCK
(但请记住,然后优化配置文件)。HTH。
答案 2 :(得分:2)