日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux网络编程 | 零拷贝 :sendfile、mmap、splice、tee

發(fā)布時間:2024/4/11 linux 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux网络编程 | 零拷贝 :sendfile、mmap、splice、tee 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 傳統(tǒng)文件傳輸?shù)膯栴}
  • Linux中實現(xiàn)零拷貝的方法


傳統(tǒng)文件傳輸?shù)膯栴}

在網(wǎng)絡編程中,如果我們想要提供文件傳輸?shù)墓δ?#xff0c;最簡單的方法就是用read將數(shù)據(jù)從磁盤上的文件中讀取出來,再將其用write寫入到socket中,通過網(wǎng)絡協(xié)議發(fā)送給客戶端。

ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count);

但是就是這兩個簡單的操作,卻帶來了大量的性能丟失

例如我們的服務器需要為客戶端提供一個下載操作,此時的操作如下

從上圖可以看出,雖然僅僅只有這兩行代碼,但是卻在發(fā)生了四次用戶態(tài)和內(nèi)核態(tài)的上下文切換,以及四次數(shù)據(jù)拷貝,也就是在這個地方產(chǎn)生了大量不必要的損耗。

那么為什么會發(fā)生這些操作呢?

上下文切換

由于read和recv是系統(tǒng)調(diào)用,所以每次調(diào)用該函數(shù)我們都需要從用戶態(tài)切換至內(nèi)核態(tài),等待內(nèi)核完成任務后再從內(nèi)核態(tài)切換回用戶態(tài)。

數(shù)據(jù)拷貝
上面也說了,由于數(shù)據(jù)的讀取與寫入都是由系統(tǒng)進行的,那么我們就得將數(shù)據(jù)從用戶的緩沖區(qū)中拷貝到內(nèi)核,

  • 第一次拷貝:將磁盤中的數(shù)據(jù)拷貝到內(nèi)核的緩沖區(qū)中
  • 第二次拷貝:內(nèi)核將數(shù)據(jù)處理完,接著拷貝到用戶緩沖區(qū)中
  • 第三次拷貝:此時需要通過socket將數(shù)據(jù)發(fā)送出去,將用戶緩沖區(qū)中的數(shù)據(jù)拷貝至內(nèi)核中socket的緩沖區(qū)中
  • 第四次拷貝:把內(nèi)核中socket緩沖區(qū)的數(shù)據(jù)拷貝到網(wǎng)卡的緩沖區(qū)中,通過網(wǎng)卡將數(shù)據(jù)發(fā)送出去。

所以要想優(yōu)化傳輸性能,就要從減少數(shù)據(jù)拷貝和用戶態(tài)內(nèi)核態(tài)的上下文切換下手,這也就是零拷貝技術(shù)的由來。

什么是零拷貝呢?
零拷貝的主要任務就是避免CPU將數(shù)據(jù)從一塊存儲中拷貝到另一塊存儲,主要就是利用各種技術(shù),避免讓CPU做大量的數(shù)據(jù)拷貝任務,以此減少不必要的拷貝。或者借助其他的一些組件來完成簡單的數(shù)據(jù)傳輸任務,讓CPU解脫出來專注別的任務,使得系統(tǒng)資源的利用更加有效

Linux中實現(xiàn)零拷貝的方法

Linux中實現(xiàn)零拷貝的方法主要有以下幾種,下面一一對其進行介紹

  • sendfile
  • mmap
  • splice
  • tee
  • sendfile
    sendfile函數(shù)的作用是直接在兩個文件描述符之間傳遞數(shù)據(jù)。由于整個操作完全在內(nèi)核中(直接從內(nèi)核緩沖區(qū)拷貝到socket緩沖區(qū)),從而避免了內(nèi)核緩沖區(qū)和用戶緩沖區(qū)之間的數(shù)據(jù)拷貝。

    需要注意的是,in_fd必須是一個支持類似mmap函數(shù)的文件描述符,不能是socket或者管道,而out_fd必須是一個socket,由此可見sendfile是專門為了在網(wǎng)絡上傳輸文件而實現(xiàn)的函數(shù)。

    #include <sys/sendfile.h> ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

    參數(shù):
    out_fd : 待寫入內(nèi)容的文件描述符
    in_fd : 待讀出內(nèi)容的文件描述符
    offset : 文件的偏移量
    count : 需要傳輸?shù)淖止?jié)數(shù)

    返回值:
    成功:返回傳輸?shù)淖止?jié)數(shù)
    失敗:返回-1并設置errno


    mmap
    mmap用于申請一段內(nèi)存空間,也就是我們在進程間通信中提到過的共享內(nèi)存,通過將內(nèi)核緩沖區(qū)的數(shù)據(jù)映射到用戶空間中,兩者通過共享緩沖區(qū)直接訪問統(tǒng)一資源,此時內(nèi)核與用戶空間就不需要再進行任何的數(shù)據(jù)拷貝操作了

    其中mmap用于申請空間,額munmap用于釋放這段空間。

    #include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); int munmap(void *addr, size_t length);

    參數(shù):
    addr : 內(nèi)存的起始地址,如果設置為空則系統(tǒng)會自動分配
    length : 指定內(nèi)存段的長度
    prot : 內(nèi)存段的訪問權(quán)限,通過按位與或可以取以下幾種值

    flag : 選項
    fd : 被映射文件對應的文件描述符
    offset : 文件的偏移量
    返回值:
    成功:成功時返回指向內(nèi)存區(qū)域的指針
    失敗:返回MAP_FAILED并設置errno


    splice
    splice函數(shù)用于在兩個文件描述符之間移動數(shù)據(jù),而不需要數(shù)據(jù)在內(nèi)核空間和用戶空間中來回拷貝

    需要注意的是,使用splice函數(shù)時fd_in和fd_out至少有一個是管道文件描述符,即

    #include <fcntl.h> ssize_t splice(int fd_in, loff_t *off_in, int fd_out,loff_t *off_out, size_t len, unsigned int flags);

    參數(shù):
    out_fd : 待寫入內(nèi)容的文件描述符
    off_out : 待寫入文件描述符的偏移量,如果文件描述符為管道則必須為空
    in_fd : 待讀出內(nèi)容的文件描述符
    off_in : 待讀出文件描述符的偏移量,如果文件描述符為管道則必須為空
    len : 需要復制的字節(jié)數(shù)
    flags : 選項

    返回值:
    成功:返回在兩個文件描述符之間復制的字節(jié)數(shù)
    沒有數(shù)據(jù):返回0
    失敗:返回-1并設置errno
    可能產(chǎn)生的errno


    tee
    tee函數(shù)用于在兩個管道文件描述符之間復制數(shù)據(jù),并且它是直接復制,不會將數(shù)據(jù)讀出,所以源文件上的數(shù)據(jù)仍可以用于后面的讀操作

    #include <fcntl.h> ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

    參數(shù):
    out_fd : 待寫入內(nèi)容的文件描述符
    in_fd : 待讀出內(nèi)容的文件描述符
    len : 需要復制的字節(jié)數(shù)
    flags : 選項

    返回值:
    成功:返回在兩個文件描述符之間復制的字節(jié)數(shù)
    沒有數(shù)據(jù):返回0
    失敗:返回-1并設置errno


    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的Linux网络编程 | 零拷贝 :sendfile、mmap、splice、tee的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。