我正在尝试使用 splice ( man 2 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.
但是,我相信这些条件都不适用。我正在使用 Fedora 15(内核 2.6.40-4),所以我相信所有文件系统都支持 splice()。目标文件在第一次调用 splice 时应该是无关紧要的,但为了完整起见,我将通过open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_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;
sock_fd 由以下伪代码初始化:
int sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK);
bind(sock_fd, ...);
可能相关的是此代码片段在 libevent 循环中运行。libevent 使用 epoll() 来确定 UDP 套接字是否热。