linux PCB数组,Linux中的系统IO函数
一、整體大綱
二、 系統IO函數
1. 一些概念
文件描述符
PCB
C庫函的IO緩沖區
1)?文件描述符
int 類型
一個進程最多可打開多少文件
2)?pcb
進程控制塊
在其中有一個文件描述符表 -- 數組[1024]
C庫IO函數工作流程:
pcb和文件描述符:
2. 虛擬地址空間
虛擬地址空間就是程序啟動起來之后從硬盤上會有一塊虛擬內存分配出來。
cpu 為什么要使用虛擬地址空間與物理地址空間映射?解決了什么樣的問題?
1)方便編譯器和操作系統安排程序的地址分布。
程序可以使用一系列相鄰的虛擬地址來訪問物理內存中不相鄰的大內存緩沖區。通過虛擬地址空間與物理地址空間映射解決不連續的緩沖區的問題。
2)方便進程之間隔離
不同進程使用的虛擬地址彼此隔離。一個進程中的代碼無法更改正在由另一進程使用的物理內存。
3)方便OS使用你那可憐的內存。
程序可以使用一系列虛擬地址來訪問大于可用物理內存的內存緩沖區。當物理內存的供應量變小時,
內存管理器會將物理內存頁(通常大小為 4 KB)保存到磁盤文件。數據或代碼頁會根據需要在物理內存與磁盤之間移動。
虛擬地址空間的布局如下:
0-3G是用戶空間? ? ? ? 3-4G是內核空間
用戶區? ? ? ? ? ? ? ? ? ? ? ? 內核區
代碼段
已經初始化的全局變量
未被初始化的全局變量
堆 -- 從下往上
共享庫
棧 - 從上往下
環境變量
內核區
3. C庫函數與系統函數的關系
FD:文件描述符 FP_POS:文件指針 BUFFER:緩沖區
write對0-3G的用戶空間進行操作 sys_write()對3-4G的內核空間進行操作
4. IO函數介紹
1)open
查看 man 2 open
頭文件:
#include #include#include
函數原型:
int open(const char *pathname, intflags);int open(const char *pathname, int flags, mode_t mode);
參數說明
pathname 文件名
flags
必選項:
O_RDONLY 只讀
O_WRONLY 只寫
O_RDWR 讀寫
可選項:
O_APPEND 追加
O_CREAT 創建文件
O_EXCL和O_CREATE一起使用,如果文件存在則報錯
O_NONBLOCK 非阻塞
Mode 權限位,最終(mode&~umask)
返回值:
成功:返回最小的可用文件描述符
失敗:返回-1,并且設置errno
open函數中的errno:
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n")12 return -1
13 }14 int fd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY, 0666);15 close(fd);16
17 return 0;18 }
使用open實現一個touch功能
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7
8 int main(int argc, char *argv[])9 {10 int num = 3;11 char filename[128] = {0};12 while(1)13 {14 sprintf(filename, "temp_%04d", num++);15 if (open(filename, O_RDONLY|O_CREAT, 0666) < 0)16 {17 perror("open err:");18 break;19 }20 }21 printf("num == %d\n", num);22
23 return 0;24 }
一個進程打開的最大文件數(1024)
2)close
作用:關閉文件描述符
頭文件:
#include
函數原型:
int close(int fd);
參數說明:
fd文件描述符
返回值:
成功:返回0
失敗:返回-1,并且設置errno
3)read讀
頭文件
#include
函數原型
ssize_t read(int fd, void *buf, size_t count);
參數說明
fd 文件描述符
buf緩沖區
count緩沖區大小
返回值
失敗:返回-1,設置errno
成功:返回讀到的字節數
0代表讀到文件末尾
非阻塞的情況下read返回-1,但是此時需要判斷error的值。
4)write寫
頭文件
#include
函數原型
ssize_t write(int fd, const void *buf, size_t count);
參數說明:
fd文件描述符
buf緩沖區
count緩沖區大小
返回值
失敗:返回-1,設置errno
成功:返回寫入的字節數
0代表未寫入
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n")12 return -1
13 }14 int fd = open(argv[1], O_RDONLY);15 char buf[256] = {0};16 int ret = 0;17 while ((ret = read(fd, buf, ziseof(buf))) != 0)18 {19 if (ret == -1)20 {21 perror("read err:");22 return -1;23 }24 else
25 {26 write(STDOUT_FILENO, buf, ret);27 }28 }29
30 close(fd);31
32 return 0;33 }
實現一個cat功能
需求:給一個文件中寫入內容,寫完之后打開該文件再讀取寫入的內容?
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_RDWR|O_CREAT, 0666);15
16 char data[12] = "hello world";17 write(fd, data, sizeof(data));18
19 char buf[256] = {0};20 int ret = 0;21 while ((ret = read(fd, buf, sizeof(buf))) != 0)22 {23 if (ret == -1)24 {25 perror("read err:");26 return -1;27 }28 else
29 {30 write(STDOUT_FILENO, buf, ret); //STDIN_FILENO, STDERR_FILENO
31 }32 }33
34 close(fd);35
36 return 0;37 }
bug版本
結果:內容寫入到文件中,但是并未按預期輸出到屏幕上。
原因:是由于write完成之后,fd到了文件末尾,因此read時到了文件末尾,無法讀取文件數據
解決方法:寫完之后將文件指針設置到文件開頭,使用請看下文要介紹的lseek函數。
5)lseek寫
頭文件
#include #include
函數原型
off_t lseek(int fd, off_t offset, int whence);
參數說明
fd文件描述符
offset偏移量
whence:
SEEK_SET 文件開始位置
SEEK_CUR 文件當前位置
SEEK_END 文件結尾
返回值
失敗:返回-1,設置errno
成功:返回當前位置到文件開頭的長度
lseek作用
移動文件讀寫位置
計算文件大小
拓展文件
示例:
a.?移動文件讀寫位置
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_RDWR|O_CREAT, 0666);15
16 char data[12] = "hello world";17 write(fd, data, sizeof(data));18 //文件讀寫位置此時在末尾19 //需要移動讀寫位置
20 lseek(fd, 0, SEEK_SET); //將fd移動到文件頭
21
22 char buf[256] = {0};23 int ret = 0;24 while ((ret = read(fd, buf, sizeof(buf))) != 0)25 {26 if (ret == -1)27 {28 perror("read err:");29 return -1;30 }31 else
32 {33 write(STDOUT_FILENO, buf, ret); //STDIN_FILENO, STDERR_FILENO
34 }35 }36
37 close(fd);38
39 return 0;40 }
修改上例的bug(寫入文件內容并讀取文件內容打印到屏幕)
b.?計算文件大小
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_RDONLY);15
16 int ret = lseek(fd, 0, SEEK_END); //將fd移動到文件頭
17 printf("file size is %d\n", ret); //注意實際讀到的文件大小為ret-1
18
19 close(fd);20
21 return 0;22 }
計算文件大小(輸出文件字節數)
c.?拓展文件
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_WRONLY|O_CREAT, 0666);15 //拓展文件
16 int ret = lseek(fd, 1024, SEEK_END); //將fd移動到文件頭17 //需要至少寫一次,否則不能保存
18 write(fd, "a", 1);19 printf("file size is %d\n", ret);20
21 close(fd);22
23 return 0;24 }
拓展文件
阻塞的概念:
read函數在讀設備或者讀管道,或者讀網絡的時候。
輸入輸出設備對應的/dev/tty。
6)fcntl
頭文件
#include #include
函數原型
int fcntl(int fd, int cmd, ... /*arg*/ );
參數說明:
fd文件描述符
cmd 命令
返回值
不同的cmd返回值不同
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 //O_NONBLOCK設置為非阻塞
10 int fd = open("/dev/tty", O_RDWR);11 //fcntl()函數,設置非阻塞
12 int flags =fcntl(fd, F_GETFL);13 flags |=O_NONBLOCK;14 fcntl(fd, F_SETFL, flags);15
16 char buf[256] = {0};17 int ret = 0;18 while(1)19 {20 //如果沒有設置O_NONBLOCK
21 ret = read(fd, buf, sizeof(buf));22 if (ret < 0)23 {24 perror("read err:");25 printf("ret is %d\n", ret);26 }27
28 if(ret)29 {30 printf("buf is %s\n", buf);31 }32 printf("haha\n");33 sleep(1);34 }35 close(fd);36
37 return 0;38 }
使用fcntl函數實現讀非阻塞
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的linux PCB数组,Linux中的系统IO函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中分区乱了,找到了linux分
- 下一篇: linux etc 漏洞利用,漏洞利用