Udp Linux splice()返回EINVAL(“无效参数”)

Udp Linux splice()返回EINVAL(“无效参数”),udp,pipe,splice,zero-copy,Udp,Pipe,Splice,Zero Copy,我正在尝试使用splice()将数据从UDP套接字直接复制到文件。不幸的是,对splice()的第一次调用返回了EINVAL 手册页说明: EINVAL Target file system doesn't support splicing; target file is opened in append mode; neither of the descriptors refers to a pipe; or offset given for nonseekable

我正在尝试使用splice()将数据从UDP套接字直接复制到文件。不幸的是,对splice()的第一次调用返回了EINVAL

手册页说明:

EINVAL Target file system doesn't support splicing; target file is opened in
       append mode; neither of the descriptors refers to a pipe; or offset
       given for nonseekable device.
然而,我认为这些条件都不适用。我使用的是Fedora15(内核2.6.40-4),所以我相信所有文件系统都支持splice()。目标文件在第一次调用splice时应该是无关的,但为了完整性,我将通过
open(path,O|u create | O|u WRONLY | O|u TRUNC,S|u IRUSR | S|u IWUSR)
打开它。两个调用都使用管道,并且两个调用都不使用除NULL之外的偏移量

以下是我的示例代码:

int sz = splice(sock_fd, 0, mPipeFds[1], 0, 8192, SPLICE_F_MORE);
if (-1 == sz)
{
int err = errno;
LOG4CXX_ERROR(spLogger, "splice from: " << strerror(err));
return 0;
}

sz = splice(mPipeFds[0], 0, file_fd, 0, sz, SPLICE_F_MORE);
if (-1 == sz)
{
int err = errno;
LOG4CXX_ERROR(spLogger, "splice to: " << strerror(err));
}

return 0;

可能与此相关的是,此代码段正在libevent循环中运行。libevent正在使用epoll()确定UDP套接字是否热。

找到了我的答案。tl;入站端不支持dr-UDP

在谷歌搜索了足够多的信息后,我偶然发现了一个和一些文件,其中打印出了输入/输出fd类型及其支持的表格:

$ ./a.out 
in\out     pipe    reg     chr     unix    tcp    udp
pipe       yes     yes     yes     yes     yes    yes
reg        yes     no      no      no      no     no
chr        yes     no      no      no      no     no
unix       no      no      no      no      no     no
tcp        yes     no      no      no      no     no
udp        no      no      no      no      no     no

是的,它绝对不支持从UDP套接字读取,即使是在最新的内核中。下面是对内核源代码的引用

splice
调用,调用文件的
file\u操作
结构中的
splice\u read
成员

对于套接字,该结构定义为,它将
splice\u read
字段初始化为

该函数依次包含以下代码行:

if (unlikely(!sock->ops->splice_read))
    return -EINVAL;
套接字的
ops
字段是一个
struct proto_ops
。对于IPv4 UDP套接字,将其初始化为。最后,该结构没有显式初始化
struct proto_ops
splice_read
字段;i、 例如,它将其初始化为零


因此,
sock\u splice\u read
返回-EINVAL,并向上传播。

sock\u fd
初始化看起来很糟糕。检查返回值!那只是伪代码。实际代码是这样的。我已经澄清了一点。如果能在这里复制这段代码,以防止它永远丢失,那将非常好。假设它得到了支持,它将如何工作?您如何知道UDP数据报来自何处?套接字上没有连接,因此它可能来自internet上的任何位置。
if (unlikely(!sock->ops->splice_read))
    return -EINVAL;