【问题标题】:Does Linux's splice(2) work when splicing from a TCP socket?从 TCP 套接字进行拼接时,Linux 的 splice(2) 是否有效?
【发布时间】:2010-10-27 11:06:11
【问题描述】:

我一直在编写一个有趣的小程序,在 Linux 上用 C 语言通过 TCP 传输文件。程序从套接字读取文件并将其写入文件(反之亦然)。我最初使用读/写并且程序运行正常,但后来我了解了splice 并想尝试一下。

我用 splice 编写的代码在从 stdin(重定向文件)读取并写入 TCP 套接字时运行良好,但在从套接字读取和写入 stdout 时,由于 splice 将 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,所以我也有一个版本的代码fork s同时从管道读取和写入,但是和这个版本有同样的错误,更难读取。

编辑:我的内核版本是 2.6.22.18-co-0.7.3(在 XP 上运行 coLinux。)

【问题讨论】:

标签: c linux pipe


【解决方案1】:

这是什么内核版本? Linux 从 2.6.25 (commit 9c55e01c0) 开始支持从 TCP 套接字进行拼接,所以如果你使用的是早期版本,那你就不走运了。

【讨论】:

  • 听到这个消息很难过。你知道有什么替代品吗?
  • 另一种选择是读/写循环 :) 如果你要去 /to/ 套接字 sendfile() 会工作,但你只需要在这里用老式的方式来做.
【解决方案2】:

每次您从frompipes[1] 进行单个拼接时,您需要将splice_allpipes[0] 转换为tosplice_all 表示字节数刚刚读到最后一个拼接)。原因:管道代表有限的内核内存缓冲区。因此,如果字节数超过此值,您将在 splice_all(from, pipes[1], bytes) 中永久阻塞。

【讨论】:

    猜你喜欢
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 2011-10-19
    • 2017-10-27
    • 2013-07-25
    • 1970-01-01
    相关资源
    最近更新 更多