我一直在编写一个有趣的小程序,在 Linux 上用 C 语言通过 TCP 传输文件。程序从套接字读取文件并将其写入文件(反之亦然)。我最初使用读/写并且程序运行正常,但后来我了解了拼接并想尝试一下。
我用 splice 编写的代码在从 stdin(重定向文件)读取并写入 TCP 套接字时工作得很好,但在从套接字读取和写入 stdout 时,由于 splice 将 errno 设置为 EINVAL 会立即失败。手册页指出,当两个描述符都不是管道(不是这种情况)时设置了 EINVAL,为无法查找的流传递了偏移量(没有传递偏移量),或者文件系统不支持拼接,这导致我我的问题:这是否意味着 TCP 可以从管道拼接,但不能拼接?
我包括下面的代码(减去错误处理代码),希望我做错了什么。它很大程度上基于Wikipedia 的 splice 示例。
static void splice_all(int from, int to, long long bytes)
{
long long bytes_remaining;
long result;
bytes_remaining = bytes;
while (bytes_remaining > 0) {
result = splice(
from, NULL,
to, NULL,
bytes_remaining,
SPLICE_F_MOVE | SPLICE_F_MORE
);
if (result == -1)
die("splice_all: splice");
bytes_remaining -= result;
}
}
static void transfer(int from, int to, long long bytes)
{
int result;
int pipes[2];
result = pipe(pipes);
if (result == -1)
die("transfer: pipe");
splice_all(from, pipes[1], bytes);
splice_all(pipes[0], to, bytes);
close(from);
close(pipes[1]);
close(pipes[0]);
close(to);
}
附带说明一下,我认为splice_all
当文件足够大时,由于管道已填满(?),上面的内容会首先阻塞,所以我还有一个可以fork
从管道读取和写入的代码版本同一时间,但它与此版本有相同的错误并且更难阅读。
编辑:我的内核版本是 2.6.22.18-co-0.7.3(在 XP 上运行 coLinux。)