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.
ただし、これらの条件はいずれも当てはまらないと思います。私はFedora15(カーネル2.6.40-4)を使用しているので、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ソケットがホットかどうかを判別しています。