在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)
它确实应该,但是经常,没有它,您可以逃脱。
我在评论中说,返回值“通常”很重要,但是这可能太过分了。请注意,每个操作系统在这里可能会有细微的差异。我将描述很久以前的传统行为:
sendto
在流类型的已连接套接字上(SOCK_STREAM
与AF_UNIX
或AF_INET
等)基本上与send
相同:它循环执行,发送部分数据,直到有些有趣事件发生。有趣的事件包括但不限于这些:
此时sendto
调用返回。如果发送了no数据,则返回值为-1
,错误为EINTR
;如果发送了一些数据,但不是全部数据,则返回值为短计数。此行为与write
系统调用的行为相同。
[sendto
在流类型但未连接的套接字上仅以ENOTCONN
失败。
[[sendto
在连接的数据报套接字上,由于已连接(C0])而报错。
EISCONN
暂时将其连接(在通话过程中),将消息作为单个数据报发送,并成功并返回发送的长度,或者失败并不发送任何内容并返回-1和[ C0]或其他一些更适当的错误(例如,如果连接失败或目标主机拒绝该数据包或其他错误,尽管并非所有这些错误都可能在所有协议上发生)。
sendto
套接字(打包的类似流的实体)上的EMSGSIZE
的行为类似于sendto
,除了整个消息作为单个数据包发送或完全发送失败。
因此,情况1除外,SOCK_SEQPACKET
套接字上的SOCK_STREAM
可能会被中断-返回值始终为sendto
或SOCK_STREAM
。对于情况1,您可以只调用len
。在Go的正常使用中,-1
的情况永远都不会发生,因为Go运行时会将所有信号定向到进程内的专用OS级线程,这意味着只有在发送一些数据并返回时,您才能获得短暂的回报。然后远程主机突然关闭(并重置)流。即使发生write
does,OS EINTR
也会产生正确的返回值。
EINTR
系统调用更为复杂,因为它允许这么多的标志,并且在不同的系统上具有不同的返回值。 BSD文档说它返回发送的messages的数量,而Linux文档说它返回发送的bytes的数量。各种消息标志也相当依赖于OS。像Go这样的简单包装器并不能真正轻松地隐藏这些差异。 (但是,我仍然看到Go库具有write
。)