为什么 Sendto() 系统调用 return 发送的字节数?
Why doesn't the Sendto() syscall return the number of sent bytes?
在 Go 的标准库中,网络系统调用 Sendto()
如下所示:
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error)
Unix:
func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error)
但是,底层系统调用return在所有操作系统上发送的字节数(Linux, Windows),那么为什么Goreturn只报错?
它确实应该——但通常情况下,没有它你也可以逃脱。
我在评论中说过 return 值 "often" 很重要,但这可能过于强烈了。注意每个OS这里可能会有细微的差别;我要描述一个很久以前的传统行为:
sendto
在流式连接套接字上(SOCK_STREAM
与 AF_UNIX
或 AF_INET
等)与 send
:它循环发送部分数据,直到发生一些有趣的事件。有趣的事件包括但不限于这些:
- 所有数据已发送
- 信号中断发送
- 连接被另一端重置
此时sendto
调用returns。 return 值为 -1
,错误 EINTR
如果 没有 数据被发送,或者如果发送了一些数据,但不是所有数据,则为短计数.此行为与 write
系统调用的行为相同。
sendto
在流类型但未连接的套接字上失败 ENOTCONN
.
sendto
在连接的数据报套接字上出现错误,并抱怨它已经连接 (EISCONN
)。
sendto
在未连接的数据报套接字上临时连接它(在调用期间),将消息作为单个数据报发送并成功,然后 returns 发送length,或者失败并且什么都不发送和 returns -1 and EMSGSIZE
或其他一些更合适的错误(例如,如果连接失败或目标主机拒绝数据包或其他任何东西 - 尽管不是所有这些所有协议都可能发生错误)。
sendto
在 SOCK_SEQPACKET
套接字(打包的类似流的实体)上的行为有点像 SOCK_STREAM
除了整个消息作为单个数据包,或者发送完全失败。
因此,除了情况 1——sendto
在可能被中断的 SOCK_STREAM
套接字上——return 值总是 len
或 -1
.对于情况 1,您可以改为调用 write
。 EINTR
这种情况在 Go 中的正常使用中永远不会发生,因为 Go 运行时会将所有信号定向到进程中专用的 OS 级线程,这意味着您唯一可以获得短 return 是当发送了一些数据然后远程主机突然关闭(并重置)流时。即使 EINTR
确实发生了 ,OS write
也会产生正确的 return 值。
sendmsg
系统调用更为复杂,因为它允许使用如此多的标志,并且在不同的系统上具有不同的 return 值。 BSD 文档说它 return 发送了 消息的数量 而 Linux 文档说它 return 发送了 [=59] 的数量=]bytes 已发送。各种消息标志也相当依赖 OS。像 Go 这样的简单包装器并不能真正轻松地隐藏这些差异。 (但是,无论如何,我看到 Go 库有 SendmsgN
。)
在 Go 的标准库中,网络系统调用 Sendto()
如下所示:
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error)
Unix:
func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error)
但是,底层系统调用return在所有操作系统上发送的字节数(Linux, Windows),那么为什么Goreturn只报错?
它确实应该——但通常情况下,没有它你也可以逃脱。
我在评论中说过 return 值 "often" 很重要,但这可能过于强烈了。注意每个OS这里可能会有细微的差别;我要描述一个很久以前的传统行为:
sendto
在流式连接套接字上(SOCK_STREAM
与AF_UNIX
或AF_INET
等)与send
:它循环发送部分数据,直到发生一些有趣的事件。有趣的事件包括但不限于这些:- 所有数据已发送
- 信号中断发送
- 连接被另一端重置
此时sendto
调用returns。 return 值为-1
,错误EINTR
如果 没有 数据被发送,或者如果发送了一些数据,但不是所有数据,则为短计数.此行为与write
系统调用的行为相同。sendto
在流类型但未连接的套接字上失败ENOTCONN
.sendto
在连接的数据报套接字上出现错误,并抱怨它已经连接 (EISCONN
)。sendto
在未连接的数据报套接字上临时连接它(在调用期间),将消息作为单个数据报发送并成功,然后 returns 发送length,或者失败并且什么都不发送和 returns -1 andEMSGSIZE
或其他一些更合适的错误(例如,如果连接失败或目标主机拒绝数据包或其他任何东西 - 尽管不是所有这些所有协议都可能发生错误)。sendto
在SOCK_SEQPACKET
套接字(打包的类似流的实体)上的行为有点像SOCK_STREAM
除了整个消息作为单个数据包,或者发送完全失败。
因此,除了情况 1——sendto
在可能被中断的 SOCK_STREAM
套接字上——return 值总是 len
或 -1
.对于情况 1,您可以改为调用 write
。 EINTR
这种情况在 Go 中的正常使用中永远不会发生,因为 Go 运行时会将所有信号定向到进程中专用的 OS 级线程,这意味着您唯一可以获得短 return 是当发送了一些数据然后远程主机突然关闭(并重置)流时。即使 EINTR
确实发生了 ,OS write
也会产生正确的 return 值。
sendmsg
系统调用更为复杂,因为它允许使用如此多的标志,并且在不同的系统上具有不同的 return 值。 BSD 文档说它 return 发送了 消息的数量 而 Linux 文档说它 return 发送了 [=59] 的数量=]bytes 已发送。各种消息标志也相当依赖 OS。像 Go 这样的简单包装器并不能真正轻松地隐藏这些差异。 (但是,无论如何,我看到 Go 库有 SendmsgN
。)