一尘不染

从TCP套接字进行拼接时,Linux的splice(2)是否起作用?

linux

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

当我从stdin(重定向文件)读取并写入TCP套接字时,我用splice编写的代码可以完美地工作,但是当从套接字读取并写入stdout时,将spr将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。)


阅读 263

收藏
2020-06-07

共1个答案

一尘不染

这是什么内核版本?从2.6.25(提交9c55e01c0)开始,Linux就支持从TCP套接字进行拼接,因此,如果您使用的是较早的版本,那么您将很不走运。

2020-06-07