2009-05-19 37 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)