Linux Sendfile 的優勢
Sendfile 函數在兩個文件描寫敘述符之間直接傳遞數據(全然在內核中操作,傳送),從而避免了內核緩沖區數據和用戶緩沖區數據之間的拷貝,操作效率非常高,被稱之為零拷貝。
Sendfile 函數的定義例如以下:
#include<sys/sendfile.h>
ssize_t sendfile(int out_fd,int in_fd,off_t*offset,size_t count);
傳統方式read/write send/recv
在傳統的文件傳輸裏面(read/write方式),在實現上事實上是比較復雜的,須要經過多次上下文的切換。我們看一下例如以下兩行代碼:
1. read(file, tmp_buf, len);
2. write(socket, tmp_buf, len);
以上兩行代碼是傳統的read/write方式進行文件到socket的傳輸。
當須要對一個文件進行傳輸的時候,其詳細流程細節例如以下:
1、調用read函數,文件數據被copy到內核緩沖區
2、read函數返回。文件數據從內核緩沖區copy到用戶緩沖區
3、write函數調用。將文件數據從用戶緩沖區copy到內核與socket相關的緩沖區。
4、數據從socket緩沖區copy到相關協議引擎。
以上細節是傳統read/write方式進行網絡文件傳輸的方式,我們能夠看到,在這個過程其中。文件數據實際上是經過了四次copy操作:
硬盤—>內核buf—>用戶buf—>socket相關緩沖區(內核)—>協議引擎
新方式sendfile
而sendfile系統調用則提供了一種降低以上多次copy。提升文件傳輸性能的方法。
Sendfile系統調用是在2.1版本號內核時引進的:
1. sendfile(socket, file, len);
執行流程例如以下:
1、sendfile系統調用,文件數據被copy至內核緩沖區
2、再從內核緩沖區copy至內核中socket相關的緩沖區
3、最後再socket相關的緩沖區copy到協議引擎
相較傳統read/write方式,2.1版本號內核引進的sendfile已經降低了內核緩沖區到user緩沖區。再由user緩沖區到socket相關 緩沖區的文件copy,而在內核版本號2.4之後,文件描寫敘述符結果被改變,sendfile實現了更簡單的方式,系統調用方式仍然一樣,細節與2.1版本號的 不同之處在於,當文件數據被拷貝到內核緩沖區時,不再將全部數據copy到socket相關的緩沖區,而是只將記錄數據位置和長度相關的數據保存到 socket相關的緩存,而實際數據將由DMA模塊直接發送到協議引擎,再次降低了一次copy操作。
Linux Sendfile 的優勢