fcntl函數詳解

功能描述:根據文件描述詞來操作文件的特性。

#include <unistd.h>
#include <fcntl.h>?
int fcntl(int fd, int cmd);?
int fcntl(int fd, int cmd, long arg);?
int fcntl(int fd, int cmd, struct flock *lock);

[描述]
fcntl()針對(文件)描述符提供控制。參數fd是被參數cmd操作(如下面的描述)的描述符。針對cmd的值,fcntl能夠接受第三個參數int arg。

[返回值]
fcntl()的返回值
與命令有關。如果出錯,所有命令都返回-1,如果成功則返回某個其他值。下列三個命令有特定返回值:F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN。
??? F_DUPFD?? 返回新的文件描述符
??? F_GETFD?? 返回相應標志
??? F_GETFL , F_GETOWN?? 返回一個正的進程ID或負的進程組ID

?

fcntl函數有5種功能:?
1. 復制一個現有的描述符(cmd=F_DUPFD).?
2. 獲得/設置文件描述符標記(cmd=F_GETFD或F_SETFD).?
3. 獲得/設置文件狀態標記(cmd=F_GETFL或F_SETFL).?
4. 獲得/設置異步I/O所有權(cmd=F_GETOWN或F_SETOWN).?
5. 獲得/設置記錄鎖(cmd=F_GETLK , F_SETLK或F_SETLKW).

1. cmd值的F_DUPFD?:?
F_DUPFD??? 返回一個如下描述的(文件)描述符:
??????? ·最小的大于或等于arg的一個可用的描述符
??????? ·與原始操作符一樣的某對象的引用
??????? ·如果對象是文件(file)的話,則返回一個新的描述符,這個描述符與arg共享相同的偏移量(offset)
??????? ·相同的訪問模式(讀,寫或讀/寫)
??????? ·相同的文件狀態標志(如:兩個文件描述符共享相同的狀態標志)
??????? ·與新的文件描述符結合在一起的close-on-exec標志被設置成交叉式訪問execve(2)的系統調用

實際上調用dup(oldfd);
等效于

??????? fcntl(oldfd, F_DUPFD, 0);

而調用dup2(oldfd, newfd);
等效于
??????? close(oldfd);
??????? fcntl(oldfd, F_DUPFD, newfd);

2. cmd值的F_GETFD和F_SETFD:??????
F_GETFD??? 取得與文件描述符fd聯合的close-on-exec標志,類似FD_CLOEXEC。如果返回值和FD_CLOEXEC進行與運算結果是0的話,文件保持交叉式訪問exec(),否則如果通過exec運行的話,文件將被關閉(arg 被忽略)??
??????
F_SETFD??? 設置close-on-exec標志,該標志以參數arg的FD_CLOEXEC位決定,應當了解很多現存的涉及文件描述符標志的程序并不使用常數 FD_CLOEXEC,而是將此標志設置為0(系統默認,在exec時不關閉)或1(在exec時關閉)????

在修改文件描述符標志或文件狀態標志時必須謹慎,先要取得現在的標志值,然后按照希望修改它,最后設置新標志值。不能只是執行F_SETFD或F_SETFL命令,這樣會關閉以前設置的標志位。?

3.?cmd值的F_GETFL和F_SETFL:???
F_GETFL??? 取得fd的文件狀態標志,如同下面的描述一樣(arg被忽略),在說明open函數時,已說明
了文件狀態標志。不幸的是,三個存取方式標志 (O_RDONLY ,?O_WRONLY , 以及O_RDWR)并不各占1位。(這三種標志的值各是0 , 1和2,由于歷史原因,這三種值互斥 — 一個文件只能有這三種值之一。) 因此首先必須用屏蔽字O_ACCMODE相與取得存取方式位,然后將結果與這三種值相比較。???????
F_SETFL??? 設置給arg描述符狀態標志,可以更改的幾個標志是:O_APPEND,O_NONBLOCK,O_SYNC 和 O_ASYNC。而fcntl的文件狀態標志總共有7個:O_RDONLY , O_WRONLY , O_RDWR , O_APPEND , O_NONBLOCK , O_SYNC和O_ASYNC

可更改的幾個標志如下面的描述:
??? O_NONBLOCK?? 非阻塞I/O,如果read(2)調用沒有可讀取的數據,或者如果write(2)操作將阻塞,則read或write調用將返回-1和EAGAIN錯誤
??? O_APPEND???? 強制每次寫(write)操作都添加在文件大的末尾,相當于open(2)的O_APPEND標志
??? O_DIRECT???? 最小化或去掉reading和writing的緩存影響。系統將企圖避免緩存你的讀或寫的數據。如果不能夠避免緩存,那么它將最小化已經被緩存了的數據造成的影響。如果這個標志用的不夠好,將大大的降低性能
??? O_ASYNC????? 當I/O可用的時候,允許SIGIO信號發送到進程組,例如:當有數據可以讀的時候

4.?cmd值的F_GETOWN和F_SETOWN:???
F_GETOWN?? 取得當前正在接收SIGIO或者SIGURG信號的進程id或進程組id,進程組id返回的是負值(arg被忽略)?????
F_SETOWN?? 設置將接收SIGIO和SIGURG信號的進程id或進程組id,進程組id通過提供負值的arg來說明(arg絕對值的一個進程組ID),否則arg將被認為是進程id

?5.?cmd值的F_GETLK, F_SETLK或F_SETLKW?獲得/設置記錄鎖的功能,成功則返回0,若有錯誤則返回-1,錯誤原因存于errno。
F_GETLK??? 通過第三個參數arg(一個指向flock的結構體)取得第一個阻塞lock description指向的鎖。取得的信息將覆蓋傳到fcntl()的flock結構的信息。如果沒有發現能夠阻止本次鎖(flock)生成的鎖,這個結構將不被改變,除非鎖的類型被設置成F_UNLCK????
F_SETLK??? 按照指向結構體flock的指針的第三個參數arg所描述的鎖的信息設置或者清除一個文件的segment鎖。F_SETLK被用來實現共享(或讀)鎖(F_RDLCK)或獨占(寫)鎖(F_WRLCK),同樣可以去掉這兩種鎖(F_UNLCK)。如果共享鎖或獨占鎖不能被設置,fcntl()將立即返回EAGAIN?????
F_SETLKW?? 除了共享鎖或獨占鎖被其他的鎖阻塞這種情況外,這個命令和F_SETLK是一樣的。如果共享鎖或獨占鎖被其他的鎖阻塞,進程將等待直到這個請求能夠完成。當fcntl()正在等待文件的某個區域的時候捕捉到一個信號,如果這個信號沒有被指定SA_RESTART, fcntl將被中斷

當一個共享鎖被set到一個文件的某段的時候,其他的進程可以set共享鎖到這個段或這個段的一部分。共享鎖阻止任何其他進程set獨占鎖到這段保護區域的任何部分。如果文件描述符沒有以讀的訪問方式打開的話,共享鎖的設置請求會失敗。

獨占鎖阻止任何其他的進程在這段保護區域任何位置設置共享鎖或獨占鎖。如果文件描述符不是以寫的訪問方式打開的話,獨占鎖的請求會失敗。

結構體flock的指針:
struct flcok?
{?
short int l_type; /* 鎖定的狀態*/

//以下的三個參數用于分段對文件加鎖,若對整個文件加鎖,則:l_whence=SEEK_SET, l_start=0, l_len=0
short int l_whence; /*決定l_start位置*/?
off_t l_start; /*鎖定區域的開頭位置*/?
off_t l_len; /*鎖定區域的大小*/

pid_t l_pid; /*鎖定動作的進程*/?
};

l_type 有三種狀態:?
F_RDLCK?? 建立一個供讀取用的鎖定?
F_WRLCK?? 建立一個供寫入用的鎖定?
F_UNLCK?? 刪除之前建立的鎖定

l_whence 也有三種方式:?
SEEK_SET?? 以文件開頭為鎖定的起始位置?
SEEK_CUR?? 以目前文件讀寫位置為鎖定的起始位置?
SEEK_END?? 以文件結尾為鎖定的起始位置


fcntl文件鎖有兩種類型:建議性鎖和強制性鎖
建議性鎖是這樣規定的:每個使用上鎖文件的進程都要檢查是否有鎖存在,當然還得尊重已有的鎖。內核和系統總體上都堅持不使用建議性鎖,它們依靠程序員遵守這個規定。
強制性鎖是由內核執行的:當文件被上鎖來進行寫入操作時,在鎖定該文件的進程釋放該鎖之前,內核會阻止任何對該文件的讀或寫訪問,每次讀或寫訪問都得檢查鎖是否存在。

系統默認fcntl都是建議性鎖,強制性鎖是非POSIX標準的。如果要使用強制性鎖,要使整個系統可以使用強制性鎖,那么得需要重新掛載文件系統,mount使用參數 -0 mand 打開強制性鎖,或者關閉已加鎖文件的組執行權限并且打開該文件的set-GID權限位。
建議性鎖只在cooperating processes之間才有用。對cooperating process的理解是最重要的,它指的是會影響其它進程的進程或被別的進程所影響的進程,舉兩個例子:
(1) 我們可以同時在兩個窗口中運行同一個命令,對同一個文件進行操作,那么這兩個進程就是cooperating? processes
(2) cat file | sort,那么cat和sort產生的進程就是使用了pipe的cooperating processes

使用fcntl文件鎖進行I/O操作必須小心:進程在開始任何I/O操作前如何去處理鎖,在對文件解鎖前如何完成所有的操作,是必須考慮的。如果在設置鎖之前打開文件,或者讀取該鎖之后關閉文件,另一個進程就可能在上鎖/解鎖操作和打開/關閉操作之間的幾分之一秒內訪問該文件。當一個進程對文件加鎖后,無論它是否釋放所加的鎖,只要文件關閉,內核都會自動釋放加在文件上的建議性鎖(這也是建議性鎖和強制性鎖的最大區別),所以不要想設置建議性鎖來達到永久不讓別的進程訪問文件的目的(強制性鎖才可以);強制性鎖則對所有進程起作用。

fcntl使用三個參數 F_SETLK/F_SETLKW, F_UNLCK和F_GETLK 來分別要求、釋放、測試record locks。record locks是對文件一部分而不是整個文件的鎖,這種細致的控制使得進程更好地協作以共享文件資源。fcntl能夠用于讀取鎖和寫入鎖,read lock也叫shared lock(共享鎖), 因為多個cooperating process能夠在文件的同一部分建立讀取鎖;write lock被稱為exclusive lock(排斥鎖),因為任何時刻只能有一個cooperating process在文件的某部分上建立寫入鎖。如果cooperating processes對文件進行操作,那么它們可以同時對文件加read lock,在一個cooperating process加write lock之前,必須釋放別的cooperating process加在該文件的read lock和wrtie lock,也就是說,對于文件只能有一個write lock存在,read lock和wrtie lock不能共存。

下面的例子使用F_GETFL獲取fd的文件狀態標志

#include<fcntl.h>
#include<unistd.h>
#include<iostream>
#include<errno.h>
using namespace std;

int main(int argc,char* argv[])
{
? int fd, var;
? //? fd=open("new",O_RDWR);
? if (argc!=2)
? {
????? perror("--");
????? cout<<"請輸入參數,即文件名!"<<endl;
? }

? if((var=fcntl(atoi(argv[1]), F_GETFL, 0))<0)
? {
???? strerror(errno);
???? cout<<"fcntl file error."<<endl;
? }

? switch(var & O_ACCMODE)
? {
?? case O_RDONLY : cout<<"Read only.."<<endl;
?????????????????? break;
?? case O_WRONLY : cout<<"Write only.."<<endl;
?????????????????? break;
?? case O_RDWR?? : cout<<"Read wirte.."<<endl;
?????????????????? break;
?? default? : break;
? }

?if (val & O_APPEND)
??? cout<<",append"<<endl;

?if (val & O_NONBLOCK)
??? cout<<",noblocking"<<endl;

?cout<<"exit 0"<<endl;

?exit(0);
}

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

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

相關文章

使用nohup讓程序永遠后臺運行

使用nohup讓程序永遠后臺運行 Unix/Linux下一般比如想讓某個程序在后臺運行&#xff0c;很多都是使用 & 在程序結尾來讓程序自動運行。比如我們要運行mysql在后臺&#xff1a; /usr/local/mysql/bin/mysqld_safe --usermysql &但是加入我們很多程序并不象mysqld一樣做…

算法(8)-leetcode-explore-learn-數據結構-鏈表

leetcode-explore-learn-數據結構-鏈表11.概述1.1 鏈表插入操作1.2 鏈表刪除操作2.設計鏈表本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-list/所…

Mysql索引優化實例講解

MYSQL描述&#xff1a;一個文章庫&#xff0c;里面有兩個表&#xff1a;category和article。category里面有10條分類數據。article里面有20萬條。article里面有一個"article_category"字段是與category里的"category_id"字段相對應的。article表里面已經把…

給自己的VIM配置

編輯 .vimrc 文件如下&#xff1a; filetype plugin on "autocmd Filetype cpp,c,java,cs set omnifunccppcomplete#Complete set nu set nocp set nobackup let g:C_AuthorName gaoke let g:C_AuthorRef gaoke let g:C_Email gaoketaomee.…

shell一文入門通

簡單來說“Shell編程就是對一堆Linux命令的邏輯化處理”。 W3Cschool 上的一篇文章是這樣介紹 Shell的 hello world 學習任何一門編程語言第一件事就是輸出HelloWord了&#xff01;下面我會從新建文件到shell代碼編寫來說下Shell 編程如何輸出Hello World。 (1)新建一個文件…

算法(9)--兩個數的最大公約數

兩個數的最大公約數1.輾轉相除法求解兩個數的最大公約數2.更相減損術求解兩個數的最大公約數3.不嚴格理解1.輾轉相除法求解兩個數的最大公約數 輾轉相除法&#xff1a;兩個正整數a和b&#xff08;a>b&#xff09;的最大公約數等于a除以b的余數與b 之間的最大公約數。–如果…

RPC編程

圖 3 說明在客戶機和服務器之間完成 RPC 涉及的步驟。 圖 3. 在客戶機和服務器之間完成 RPC 涉及的步驟服務器 RPC 應用程序初始化期間它會向 RPC 運行時庫注冊接口。需要注冊接口是因為&#xff0c;客戶機在向服務器發出遠程過程調用時&#xff0c;要檢查它是否與服務器兼容。…

synchronized使用和原理全解

synchronized是Java中的關鍵字&#xff0c;是一種同步鎖。它修飾的對象有以下幾種&#xff1a; 修飾一個方法 被修飾的方法稱為同步方法&#xff0c;其作用的范圍是整個方法&#xff0c;作用的對象是調用這個方法的對象&#xff1b; 修飾一個靜態的方法 其作用的范圍是整個…

RPC學習筆記

在查看libc6-dev軟件包提供的工具&#xff08;用 dpkg -L libc6-dev 命令&#xff09;的時候&#xff0c;發現此軟件包提供了一個有用的工具rpcgen命令。通過rpcgen的man手冊看到此工具的作用是把RPC源程序編譯成C語言源程序&#xff0c;從而輕松實現遠程過程調用。下面的例子程…

算法(10)-leetcode-explore-learn-數據結構-鏈表雙指針技巧

leetcode-explore-learn-數據結構-鏈表21.概述2.例題2.1 環形鏈表判斷2.2 環形鏈表22.3 相交鏈表2.4 刪除鏈表的倒數第N個節點3.小結本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn…

一個簡單的游戲服務器框架

最近看到百度空間的一個帖子&#xff0c;不錯&#xff0c;在這里整理下&#xff0c;轉載至我的博客里&#xff0c;開始自己慢慢琢磨寫一個框架。 我先從上層結構說起&#xff0c;一直到實現細節吧&#xff0c;想起什么就寫什么。 第一部分 服務器邏輯 服務器這邊簡單的分為三…

堆和棧的精華大總結

Java內存分配原理 棧、堆、常量池雖同屬Java內存分配時操作的區域&#xff0c;但其適用范圍和功用卻大不相同。 一般Java在內存分配時會涉及到以下區域&#xff1a; ◆寄存器&#xff1a;我們在程序中無法控制 ◆棧&#xff1a;存放基本類型的數據和對象的引用&#xff0c;但…

算法(11)-leetcode-explore-learn-數據結構-鏈表的經典問題

leetcode-explore-learn-數據結構-鏈表31.反轉一個鏈表2.移除鏈表元素3.奇偶鏈表4.回文鏈表5.小結本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-l…

探索式軟件測試

James A.Whittaker [美] 詹姆斯惠特克&#xff08;軟件測試領域絕對的大師&#xff09;著作《Exploratory Software Testing》&#xff0c;中文名《探索式軟件測試》&#xff0c;記得當時被這本書深深吸引啦&#xff08;我不知道有多少做測試的小伙伴看過這本書&#xff09;&am…

Linux線程池的設計

我設計這個線程池的初衷是為了與socket對接的。線程池的實現千變萬化&#xff0c;我得這個并不一定是最好的&#xff0c;但卻是否和我心目中需求模型的。現把部分設計思路和代碼貼出&#xff0c;以期拋磚引玉。個人比較喜歡搞開源&#xff0c;所以大家如果覺得有什么需要改善的…

算法(12)-leetcode-explore-learn-數據結構-雙鏈表的設計

leetcode-explore-learn-數據結構-鏈表4雙鏈表的設計本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-list/所有例題的編程語言為python 雙鏈表的設…

安全方面知識

什么是文件上傳漏洞 文件上傳漏洞是指 由于程序員在對用戶文件上傳部分的控制不足或者處理缺陷&#xff0c;而導致的用戶可以越過其本身權限向服務器上上傳可執行的動態腳本文件 這里上傳的文件可以是木馬&#xff0c;病毒&#xff0c;惡意腳本或者WebShell等。 這種攻擊方式是…

CE游戲外掛工具

CHEAT ENGINE(以下簡稱CE)是我見過的最優秀的游戲作弊工具。它的優點多不勝數&#xff0c;雖然單獨從搜索游 戲里面的數值來說&#xff0c;它并不比其他同類軟件強多少&#xff0c;但它不僅僅是個游戲修改工具&#xff0c;它還有其他游戲修改軟件所沒有的一些特點&#xff0c;例…

外掛編程-動作模擬技術

幾乎所有的游戲都有大量繁瑣和無聊的攻擊動作以增加玩家的 功力,還有那些數不完的迷宮,這些好像已經成為了角色游戲的代名詞。現在,外掛可以幫助玩家從這些繁瑣而無聊 的工作中擺脫出來。 1. 鼠標模擬技術 幾乎所有的游戲中都使用了鼠標來改變角色的位置和方向,玩家僅用…

算法(13)-leetcode-explore-learn-數據結構-鏈表小結

leetcode-explore-learn-數據結構-鏈表51.小結2.例題2.1合并兩個有序鏈表思路1:迭代思路2:遞歸2.2 兩數相加2.3 扁平化多級雙向鏈表2.4 復制帶隨機指針的鏈表2.5 旋轉鏈表本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode…