我一直在编写一个有趣的程序,可以通过Linux在C上通过TCP传输文件。程序从套接字读取文件并将其写入文件(反之亦然)。我最初使用读/写并且程序正常工作,但后来我了解了splice并想尝试一下。
我用splice编写的代码在从stdin(重定向文件)读取并写入TCP套接字时工作得很好,但是当从套接字读取并写入stdout时,拼接设置errno立即失败到EINVAL。手册页指出当两个描述符都不是管道(不是这种情况)时,EINVAL被设置,为无法搜索的流传递偏移量(没有传递偏移量),或文件系统不支持拼接,这导致我我的问题:这是否意味着TCP可以从管道中拼接,而不是到?
我包含下面的代码(减去错误处理代码),希望我做错了。它主要基于Wikipedia example for 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
,所以我也有一个代码版本{ {1}}同时从管道读取和写入,但它与此版本具有相同的错误,并且更难以阅读。
答案 0 :(得分:8)
这是什么内核版本?自2.6.25(提交9c55e01c0)以来,Linux一直支持从TCP套接字进行拼接,所以如果你使用的是早期版本,那你就不走运了。
答案 1 :(得分:2)
每次从splice_all
到pipes[0]
进行单拼接时,您需要to
从from
到pipes[1]
( splice_all
表示最后一次拼接读取的字节数。原因:管道代表有限的内核内存缓冲区。因此,如果字节数超过该值,您将永久阻止splice_all(from, pipes[1], bytes)
。