代码之家  ›  专栏  ›  技术社区  ›  Neil Williams

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

  •  9
  • Neil Williams  · 技术社区  · 15 年前

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

    我用splice编写的代码在从stdin(重定向文件)读取和写入TCP套接字时工作得很好,但在从socket读取和写入stdout时,splice设置errno设置为einfal时会立即失败。该手册页指出,当两个描述符都不是管道时(不是这样),将为无法查找的流传递偏移量(未传递偏移量),或者文件系统不支持拼接,这就引出了我的问题:这是否意味着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)。

    2 回复  |  直到 13 年前
        1
  •  8
  •   bdonlan    15 年前

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

        2
  •  2
  •   Jonathan Graehl    13 年前

    你需要 splice_all pipes[0] to 每次你做一个 单一的 拼接从 from pipes[1] (the 拼接拼接 是指最后一个单个拼接刚刚读取的字节数)。原因:管道表示有限的内核内存缓冲区。因此,如果字节数超过该值,您将永远阻止 splice_all(from, pipes[1], bytes) .