2009-05-19 35 views
9

我已经写了一个有趣的小程序,在Linux上使用C传输文件通过TCP。程序从套接字读取文件并将其写入文件(反之亦然)。我最初使用读/写和程序工作正常,但后来我了解到splice,并想尝试一下。当从TCP套接字拼接时,Linux的拼接(2)是否工作?

当从stdin(重定向文件)读取并写入TCP套接字时,我使用splice编写的代码完美工作,但在从套接字读取并写入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块时该文件是足够大,由于管填充(?),所以我也有一个版本的代码fork的s同时读取和写入管道,但它与此版本有相同的错误,并且难以阅读。

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

+0

我成功地在Haskell中使用`splice`:http://stackoverflow.com/questions/10080670/using-gnu-linux-system-call-splice-for-zero-copy-socket-to-socket-data-转让以及:) – 2012-04-10 11:37:46

回答

8

什么内核版本这是什么?自2.6.25以来,Linux已经支持从TCP套接字拼接(提交9c55e01c0),所以如果您使用的是早期版本,那么您运气不好。

+0

这听起来很难过。你知道任何替代品吗? – 2009-05-19 21:05:42

2

您需要splice_all每次都从pipes[0]tofrompipes[1]拼接(该splice_all是字节刚刚过去的单一剪接阅读量)。原因:管道代表有限的内核内存缓冲区。所以如果字节超过这个数字,你会永远阻止你的splice_all(from, pipes[1], bytes)