SCM_RIGHTS API quirks (2019)
摘要
作者基于 Linux 实测,梳理了 SCM_RIGHTS 辅助消息在 sendmsg/recvmsg 上的若干行为怪癖:辅助消息附着在本次 sendmsg 发送的字节范围上,但接收端 recvmsg 与 sendmsg 并非一一对应,消息可能合并或拆分;收到该字节范围首字节的那次 recvmsg 会同时收到辅助消息,且会被人为限制只读到该范围末尾,即使缓冲区后面还有数据;若缓冲区装不下整条消息,下一次 recvmsg 则可越过边界读到下一条辅助消息。普通 read () 也会出现提前结束的类似模式,在边缘触发 I/O 下可能误判数据已读完。单条 SCM_RIGHTS 消息最多携带 253 个文件描述符;若辅助缓冲区不够,描述符数组会被截断,剩余描述符被丢弃并关闭,无法分多次调用拆分接收。
荐读理由
照这份实测结论,你写边缘触发 IO 时不能把短读当成数据读完的信号,否则会漏收后续数据
原文
As tested on Linux:
An SCM_RIGHTS ancillary message is "attached" to the range of data bytes sent in the same sendmsg() call.
However, as always, recvmsg() calls on the receiving end don't necessarily map 1:1 to sendmsg() calls. Messages can be coalesced or split.
The recvmsg() call that receives the first byte of the ancillary message's byte range also receives the ancillary message itself.
To prevent multiple ancillary messages being delivered at once, the recvmsg() call that receives the ancillary data will be artifically limited to read no further than the last byte in the range, even if more data is available in the buffer after that byte, and even if that later data is not actually associated with any ancillary message.
However, if the recvmsg() that received the first byte does not provide enough buffer space to read the whole message, the next recvmsg() will be allowed to read past the end of the mesage range and even into a new ancillary message's range, returning the ancillary data for the later message.
Regular read()s will show the same pattern of potentially ending early even though they cannot receive ancillary messages at all. This can mess things up when using edge triggered I/O if you assumed that a short read() indicates no more data is available.
A single SCM_RIGHTS message may contain up to SCM_MAX_FD (253) file descriptors.
If the recvmsg() does not provide enough ancillary buffer space to fit the whole descriptor array, it will be truncated to fit, with the remaining descriptors being discarded and closed. You cannot split the list over multiple calls.
这条对你有帮助吗?