Linux | 高級I/O函數

文章目錄

  • 創建文件描述符的函數
    • pipe函數
    • dup函數、dup2函數
  • 讀取或寫入數據
    • readv函數、writev函數
  • 零拷貝
    • sendfile函數
    • splice函數
    • tee函數
  • 進程間通信——共享內存
    • mmap函數 和 munmap函數
  • 控制文件描述符
    • fcntl函數


創建文件描述符的函數

pipe函數

不再贅述,詳情見我的另一篇博客。

值得一提的是,socket 基礎API中有一個 socketpair函數,能夠方便地創建雙向管道:

#include<sys/types.h>
#include<sys/socket.h>
int socketpair(int domain, int type, int protocol, inf fd[2]);
// domain只能使用 UNIX 本地域協議族 AF_UNIX,因為我們僅能在本地使用這個雙向管道。
// 成功時返回0,失敗時返回-1并設置error。

dup函數、dup2函數

這兩個函數會在 CGI服務器 中用到。CGI服務器: 主要是通過把服務器本地標準輸入、輸出或者文件重定向到網絡連接中,以達到向標準輸入、輸出緩沖區中輸入的信息,能在網絡連接中發送的效果。

#include<unistd.h>
int dup( int file_descriptor );
int dup2( int file_descriptor_one, int file_descriptor_two );
  • dup: 創建一個新的文件描述符,該文件描述符和原有文件描述符 file_descriptor 指向相同的文件、管道或網絡連接。返回的文件描述符總是取系統當前可用的最小整數值。
  • dup2:dup 類似,只是返回第一個不小于 file_descriptor_two 的整數值。

兩個系統調用失敗時都返回 -1,并設置 error

通過 dupdup2 創建的文件描述符并不繼承原文件描述符的屬性。比如:close-on-execnon-blocking 等。

dup 實現一個基本的 CGI服務器 的局部代碼:

close( STDOUT_FILENO );
dup( connfd );
printf( "hello\n" );
close( connfd );

流程:

  1. 先關閉標準輸出文件描述符 STDOUT_FILENO (其值是1);
  2. 通過 dup 復制 socket 文件描述符 connfd
  3. 由于 dup 總是返回系統中最小的可用文件描述符,所以它的返回值實際上是 1 ,即之前關閉的標準輸出文件描述符的值;
  4. 服務器輸出到標準輸出的內容(“hello”)就會直接發送到與客戶端對應的 socket 上,因此 printf 調用的輸出將被客戶端獲得,而不是顯示在服務器程序的終端上。

讀取或寫入數據

readv函數、writev函數

  • readv函數: 將數據從文件描述符讀到分散的內存塊中,即分散讀;
  • writev函數: 將多塊分配的內存數據一并寫入文件描述符中,即集中寫。

相當于簡化版的 recvmsgsendmsg

#include<sys/uio.h>
ssize_t readv( int fd, const struct iovec* vector, int count );
ssize_t weitev( int fd, const struct iovec* vector, int count );
// fd:被操作的目標文件描述符
// vector:iovec結構數組,iovec封裝了一塊內存的起始位置和長度
// count:vector數組的長度,即有多少塊內存數據需要從fd讀出或寫入到fd
// 成功時返回讀出/寫入fd的字節數,失敗則返回-1并試著errno。

零拷貝

sendfile函數

sendfile函數: 用于在兩個文件描述符之間直接傳遞數據(完全在內核中操作),從而避免了內核緩沖區和用戶緩沖區之間的數據拷貝,效率很高。被稱為 零拷貝

#include<sys/sendfile.h>
ssize_t sendfile( int out_fd, int in_fd, off_t* offset, size_t count );
// out_fd:待寫入內容的文件描述符,必須是一個socket
// in_fd:待讀出內容的文件描述符,必須是一個支持類似mmap函數的文件描述符,即必須指向真實的文件,不能是socket和管道
// offset:指定從讀入文件流的哪個位置開始讀,如果為空,則使用讀入文件流默認的起始位置
// count:傳輸的字節數
// 成功時返回傳輸的字節數,失敗返回-1,并設置errno

sendfile 幾乎是專門為在網絡上傳輸文件而設計的。


splice函數

splice函數: 本質就是借助管道描述符在兩個文件之間移動數據,也是零拷貝

#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 );
// fd_in:待輸入數據的文件描述符
// off_in:如果fd_in是一個管道描述符,那么off_in必須被設置為NULL;反之,如果fd_in不是一個管道描述符(如socket),那么off_in表示從輸入數據流開始讀取數據的起始位置。總而言之,若off_in不為NULL,則它將指出具體的偏移位置。
// fd_out/off_out:與fd_in/off_in類似,不過用于輸出數據流。
// len:移動數據的長度
// flags:控制數據的移動方式

使用 splic函數fd_infd_out 必須至少有一個是管道文件描述符splice函數 調用成功時返回移動字節的數量。可能返回 0,表示沒有數據需要移動,這發生在從管道中讀取數據(fd_in 是管道文件描述符)而管道沒有被寫入任何數據時(fd_out 不是管道文件描述符)。splice函數失敗時返回 -1 并設置 errno

常見的 errno

errno含義
EBADF參數所指文件描述符有錯
ENOMEM內存不夠
EINVAL目標文件系統不支持splice,或者目標文件以追加方式打開,或者兩個文件描述符都不是管道文件描述符,或者某個 offset 參數被用于不支持隨機訪問的設備(如字符設備)
ESPIPE參數 fd_in(或fd_out) 是管道文件描述符,而 off_in(或off_out) 不為NULL

tee函數

tee函數: 兩個管道文件描述符之間的 零拷貝。它不消耗數據,因此源文件描述符上的數據仍可以用于后續的讀操作

#include<fcntl.h>
ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
// 參數含義同splice,但 fd_in 和 fd_out 必須同時是管道文件描述符
// 成功時返回兩個文件之間復制的數據數量(字節數),返回0表示沒有復制任何數據,tee失敗返回-1并設置errno。

tee 常和 splice 一起用,splice非管道管道綁定,teesplice 操作后得到的管道綁定在一起。


進程間通信——共享內存

mmap函數 和 munmap函數

  • mmap函數: 申請一段內存空間作為進程間通信的共享內存,也可以將文件直接映射到其中。
  • munmap函數: 釋放由 mmap 創建的內存空間。
#include<sys/mman.h>
void* mmap( void* start, size_t length, int prot, int flags, int fd, off_t offset );
int munmap( void* start, size_t length );
// start:起始地址,為NULL時由系統自動分配一個地址。
// length:指定內存段的長度。
// prot:設置內粗段的訪問權限,可取以下值的按位或:
//  PROT_READ,內存段可讀。
//  PROT_WRITE,內存段可寫。
//  PROT_EXEC,內存段可執行。
//  PROT_NONE,內存段不能被訪問。
// flags:控制內存段內容被修改后程序的行為。
// fd:被映射文件對應的文件描述符,一般通過open調用獲得。
// offset:參數設置從文件的何處開始映射(對于不需要讀入整個文件的情況)。
// 成功時返回0,失敗返回-1并設置errno。

mmap 的 flags 參數的常用值及其含義:

常用值含義
MAP_SHARED進程間共享這段內存,對該內存段的修改將反映到被映射的文件中。提供了進程間共享內存的 POSIX 方法
MAP_PRIVATE內存段為調用進程所私有,所有修改不會反映到被映射的文件中
MAP_ANONYMOUS這段內存不是從文件映射而來的,其內容被初始化為全0。此時 mmap 最后兩個參數將被忽略。
MAP_FIXED內存段必須位于 start 指定的地址處,start 必須是內存頁面大小(4096字節=4KB)的整數倍
MAP_HUGETLB按照“大內存頁面”來分配內存空間,“大內存頁面”由 /proc/meminfo 文件來擦查看

控制文件描述符

fcntl函數

fcntl函數: 全名 file control ,提供了對文件描述符的各種控制操作(類似于系統調用 ioctl,但 ioctlfcntl 提供的控制更多。)但是 fcntlPOSIX 規定的首選方法。

#include<fcntl.h>
int fcntl(int fd, int cmd, ...);
// fd:被操作的文件描述符
// cmd:執行何種操作
// 有可能需要第三個可選參數 arg
// 成功時返回值根據操作不同有所不同,失敗時返回-1并設置errno

將文件描述符設置為非阻塞的:

int setnonblocking( int fd ){// F_GETFL 獲取 fd 的標志,成功時返回 fd 的標志int old_option = fcntl(fd, F_GETFL); // 獲取文件描述符舊的狀態標志int new_option = old_option | O_NONBLOCK; // 設置非阻塞標志fcntl(fd, F_SETFL, new_option); // F_SETFL 設置 fd 的標志return old_option; // 返回文件描述符舊的狀態標志,以便日后恢復該狀態標志
}

題外話:SIGIOSIGURG 這兩個信號與其他 Linux 信號不同,他們必須與某個文件描述符相關聯方可使用:

  • 被關聯文件描述符可讀可寫時,系統將觸發 SIGIO 信號。
  • 被關聯文件描述符是一個 socket有帶外數據可讀時,系統將觸發 SIGURG 信號。

這兩個信號就是通過 fcntl函數 與文件描述符關聯的,具體做法是:fcntl函數 為目標文件描述符指定宿主進程進程組,被指定的宿主進程進程組去捕獲這兩個信號。

特別的,使用 SIGIO 時,還需利用 fcntl 設置其 O_ASYNC標志(異步I/O標志,不過SIGIO信號模型并非真正意義上的異步I/O模型)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443730.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443730.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443730.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布式理論:CAP、BASE | 分布式存儲與一致性哈希

文章目錄分布式理論CAP定理BASE理論分布式存儲與一致性哈希簡單哈希一致性哈希虛擬節點分布式理論 CAP定理 一致性&#xff08;Consistency&#xff09;&#xff1a; 在分布式系統中的所有數據副本&#xff0c;在同一時刻是否一致&#xff08;所有節點訪問同一份最新的數據副…

Tomcat服務器性能優化

一、概述 本文檔主要介紹了Tomcat的性能調優的原理和方法。可作為公司技術人員為客戶Tomcat系統調優的技術指南&#xff0c;也可以提供給客戶的技術人員作為他們性能調優的指導手冊。 二、調優分類 由于Tomcat的運行依賴于JVM&#xff0c;從虛擬機的角度我們把Tomcat的調整分為…

分布式系統概念 | 分布式事務:2PC、3PC、本地消息表

文章目錄分布式事務2PC&#xff08;二階段提交協議&#xff09;執行流程優缺點3PC&#xff08;三階段提交協議&#xff09;執行流程優缺點本地消息表&#xff08;異步確保&#xff09;分布式事務 分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分…

數據結構算法 | 單調棧

文章目錄算法概述題目下一個更大的元素 I思路代碼下一個更大元素 II思路代碼132 模式思路代碼接雨水思路算法概述 當題目出現 「找到最近一個比其大的元素」 的字眼時&#xff0c;自然會想到 「單調棧」 。——三葉姐 單調棧以嚴格遞增or遞減的規則將無序的數列進行選擇性排序…

最長下降子序列

文章目錄題目解法DP暴搜思路代碼實現貪心二分思路代碼實現題目 給出一組數據 nums&#xff0c;求出其最長下降子序列&#xff08;子序列允許不連續&#xff09;的長度。&#xff08;類似于lc的最長遞增子序列&#xff09; 示例&#xff1a; 輸入&#xff1a; 6 // 數組元素個…

Linux 服務器程序規范、服務器日志、用戶、進程間的關系

文章目錄服務器程序規范日志rsyslogd 守護進程syslog函數openlog函數setlogmask函數closelog函數用戶進程間的關系進程組會話系統資源限制改變工作目錄和根目錄服務器程序后臺化服務器程序規范 Linux 服務器程序一般以后臺進程&#xff08;守護進程[daemon]&#xff09;形式運…

IO模型 :阻塞IO、非阻塞IO、信號驅動IO、異步IO、多路復用IO

文章目錄IO模型阻塞IO非阻塞IO信號驅動IO多路復用IO異步IOIO模型 根據各自的特性不同&#xff0c;IO模型被分為阻塞IO、非阻塞IO、信號驅動IO、異步IO、多路復用IO五類。 最主要的兩個區別就是阻塞與非阻塞&#xff0c;同步與異步。 阻塞與非阻塞 阻塞與非阻塞最主要的區別就…

Tomcat服務器集群與負載均衡實現

一、前言 在單一的服務器上執行WEB應用程序有一些重大的問題&#xff0c;當網站成功建成并開始接受大量請求時&#xff0c;單一服務器終究無法滿足需要處理的負荷量&#xff0c;所以就有點顯得有點力不從心了。另外一個常見的問題是會產生單點故障&#xff0c;如果該服務器壞掉…

Linux服務器 | 事件處理模式:Reactor模式、Proactor模式

文章目錄Reactor模式Proactor模式同步I/O模型模擬Proactor模式兩者的優缺點ReactorProactor同步I/O模型通常用于實現 Reactor 模式&#xff0c;異步I/O模型通常用于實現 Proactor 模式。&#xff08;不是絕對的&#xff0c;同步I/O也可模擬出 Proactor 模式&#xff09; React…

Linux服務器 | 服務器模型與三個模塊、兩種并發模式:半同步/半異步、領導者/追隨者

文章目錄兩種服務器模型及三個模塊C/S模型P2P模型I/O處理單元、邏輯單元、存儲單元并發同步與異步半同步/半異步模式變體&#xff1a;半同步/半反應堆模式改進&#xff1a;高效的半同步/半異步模式領導者/追隨者模式組件 &#xff1a;句柄集、線程集、事件處理器工作流程兩種服…

香農信息熵之可憐的小豬

文章目錄題目解析香農熵公式樣例具體分析代碼題目 有 n 桶液體&#xff0c;其其中 正好 有一桶含有毒藥&#xff0c;其裝的都是水。它們從外觀看起來都一樣。為了弄清楚哪只水桶含有毒藥&#xff0c;你可以喂一些豬喝&#xff0c;通過觀察豬是否會死進行判斷&#xff0c;實驗對…

字符串匹配之KMP(KnuthMorrisPratt)算法(圖解)

文章目錄最長相等前后綴next數組概念代碼實現圖解GetNext中的回溯改進代碼實現代碼復雜度分析最長相等前后綴 給出一個字符串 ababa 前綴集合&#xff1a;{a, ab, aba, abab} 后綴集合&#xff1a;{a, ba, aba, baba} 相等前后綴 即上面用同樣顏色標識出來的集合元素&#…

linux下tomcat6.0與jdk安裝詳細步驟

安裝Tomcat6.0和JDK1.6 在linux系統上安裝tomcat和jdk應該說是我學習linux知識的第一課了&#xff0c;之前只 是聽說過&#xff0c;從沒接觸過&#xff0c;但我們公司項目都是部署在linux系統上的&#xff0c;那天上司突 然給我發了幾個文檔&#xff0c;讓我看一下&#xff…

Android入門(一) | Android Studio的配置與使用

文章目錄安裝配置Android Studio使用Android Studio模擬器更改Android SDK的路徑Hello World&#xff01;安裝配置Android Studio 從這一步開始&#xff1a; 一直點 next 即可&#xff0c;直到存儲路徑的選擇上&#xff0c;可以放到非 C 盤&#xff0c;這里我放到 D 盤了&am…

Android 入門(四) | Intent 實現 Activity 切換

文章目錄Intent顯式 Intent定義兩個 xml 文件android:orientationmatch_parent 和 wrap_contentIntent函數定義兩個 Activity隱式 Intent更多隱式 Intent 的用法用隱式 Intent 打開系統瀏覽器自建 Activity 以響應打開網頁的 Intent向下一個活動傳遞數據返回數據給上一個活動In…

Android入門(二) | 項目目錄及主要文件作用分析

文章目錄項目目錄分析app目錄分析AndroidManifest.xml 分析MainActivity.kt 分析build.gradle 分析最外層目錄下的 build.gradleapp 目錄下的 build.gradle項目目錄分析 我們來看一下 src/main/res 下的一些文件&#xff1a; .gradle 和 .idea &#xff1a;這兩個目錄下放置…

Android入門(三) | Android 的日志工具 Logcat

文章目錄日志工具類 android.util.LogLogcat 中的過濾器日志工具類 android.util.Log Log 從屬日志工具類 android.util.Log &#xff0c;該類提供了五個方法供我們打印日志&#xff1a; Log.v() &#xff1a;用于打印那些最為瑣碎的、意義最小的日志信息。對應級別 verbose&…

Android 客戶端與服務器交互方式

突然想到一個問題就是Android客戶端與服務器交互有幾種方式&#xff0c;因為在腦袋里想當然的就是webservices和json。要在Android手機客戶端與pc服務器交互&#xff0c;需要滿足下面幾種條件&#xff1a;跨平臺、傳輸數據格式標準、交互方便...。 為了與服務器通訊其實無非就…

Android入門(五) | Activity 的生命周期

文章目錄Activity 的狀態及生命周期實現管理生命周期FirstActivitySecondActivityDialogActivity運行結果舊活動被回收了還能返回嗎&#xff1f;Activity 的狀態及生命周期 Android 的應用程序運用 棧&#xff08;Back Stack&#xff09; 的思想來管理 Activity&#xff1a; …

Android入門(六) | Activity 的啟動模式 及 生產環境中關于 Activity 的小技巧

文章目錄Activity 的啟動模式standardsingleTopsingleTasksingleInstance技巧了解當前界面是哪個 Activity隨時隨地退出程序啟動活動的最佳寫法Activity 的啟動模式 standard&#xff1a;默認的啟動方式&#xff0c;每次啟動一個活動都會重新創建singleTop&#xff1a;如果該活…