Linux I/O 系统调用完整对比分析

Linux 提供了丰富的 I/O 系统调用,每种都有其特定的用途和优势。本文将详细分析这些系统调用的特点、使用场景和性能特征。

  1. 概述

Linux 提供了丰富的 I/O 系统调用,每种都有其特定的用途和优势。本文将详细分析这些系统调用的特点、使用场景和性能特征。

  1. 系统调用详细对比

2.1 基本读写函数

pread/pwrite

1
2
3
4
5
6
#include <unistd.h>

// 位置指定读取/写入
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int int fd, const void *buf, size_t count, off_t offset);

特点:

  • 原子操作(读取/写入 + 位置指定)

  • 不改变文件描述符的当前位置

  • 线程安全

read/write

1
2
3
4
5
6
#include <unistd.h>

// 基本读取/写入
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

特点:

  • 最基本的 I/O 操作

  • 会改变文件描述符的当前位置

  • 相对简单但功能有限

2.2 分散/聚集 I/O 函数

preadv/pwritev

1
2
3
4
5
6
#include <sys/uio.h>

// 位置指定的分散读取/聚集写入
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);

preadv2/pwritev2

1
2
3
4
5
6
7
8
9
#define _GNU_SOURCE
#include <sys/uio.h>

// 带标志的增强版分散/聚集 I/O
ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt,
off_t offset, int flags);
ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt,
off_t offset, int flags);

2.3 资源限制函数

prlimit64

1
2
3
4
5
6
7
#include <sys/resource.h>

// 获取/设置进程资源限制
int prlimit64(pid_t pid, int resource,
const struct rlimit64 *new_limit,
struct rlimit64 *old_limit);

  1. 功能对比表

函数位置指定分散/聚集标志控制原子性跨平台read/write❌❌❌⚠️✅pread/pwrite✅❌❌✅✅readv/writev❌✅❌⚠️✅preadv/pwritev✅✅❌✅✅preadv2/pwritev2✅✅✅✅❌prlimit64❌❌❌❌✅

  1. 实际示例代码

4.1 基础读写对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <string.h>
#include <errno.h>
#include <time.h>

// 创建测试文件
void create_test_file(const char *filename) {
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("创建文件失败");
return;
}

const char *content =
"Line 1: This is the first line of test data.\n"
"Line 2: This is the second line of test data.\n"
"Line 3: This is the third line of test data.\n"
"Line 4: This is the fourth line of test data.\n"
"Line 5: This is the fifth and final line.\n";

write(fd, content, strlen(content));
close(fd);
printf("创建测试文件: %s\n", filename);
}

// read/pread 性能对比
void compare_basic_io(const char *filename) {
int fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
return;
}

char buffer&#91;100];
ssize_t bytes_read;
struct timespec start, end;

printf("\n=== 基础 I/O 对比 ===\n");

// 使用 read (会改变文件位置)
printf("1. read 测试:\n");
clock_gettime(CLOCK_MONOTONIC, &start);
bytes_read = read(fd, buffer, 50);
clock_gettime(CLOCK_MONOTONIC, &end);
buffer&#91;bytes_read] = '\0';
printf(" 读取 %zd 字节: %.30s...\n", bytes_read, buffer);
printf(" 当前文件位置: %ld\n", (long)lseek(fd, 0, SEEK_CUR));

// 使用 pread (不改变文件位置)
printf("2. pread 测试:\n");
clock_gettime(CLOCK_MONOTONIC, &start);
bytes_read = pread(fd, buffer, 50, 0); // 从开头读取
clock_gettime(CLOCK_MONOTONIC, &end);
buffer&#91;bytes_read] = '\0';
printf(" 读取 %zd 字节: %.30s...\n", bytes_read, buffer);
printf(" 文件位置仍为: %ld\n", (long)lseek(fd, 0, SEEK_CUR));

close(fd);
}

// 分散/聚集 I/O 示例
void demonstrate_vector_io(const char *filename) {
int fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
return;
}

printf("\n=== 分散/聚集 I/O 示例 ===\n");

// 设置分散读取缓冲区
char buffer1&#91;20], buffer2&#91;30], buffer3&#91;25];
struct iovec iov&#91;3];

iov&#91;0].iov_base = buffer1;
iov&#91;0].iov_len = sizeof(buffer1) - 1;

iov&#91;1].iov_base = buffer2;
iov&#91;1].iov_len = sizeof(buffer2) - 1;

iov&#91;2].iov_base = buffer3;
iov&#91;2].iov_len = sizeof(buffer3) - 1;

printf("分散读取设置:\n");
printf(" 缓冲区1: %zu 字节\n", iov&#91;0].iov_len);
printf(" 缓冲区2: %zu 字节\n", iov&#91;1].iov_len);
printf(" 缓冲区3: %zu 字节\n", iov&#91;2].iov_len);

// 使用 preadv 一次性读取到多个缓冲区
ssize_t total_bytes = preadv(fd, iov, 3, 0); // 从文件开头开始读取
printf("总共读取: %zd 字节\n", total_bytes);

if (total_bytes > 0) {
buffer1&#91;iov&#91;0].iov_len] = '\0';
buffer2&#91;iov&#91;1].iov_len] = '\0';
buffer3&#91;iov&#91;2].iov_len] = '\0';

printf("读取结果:\n");
printf(" 缓冲区1: %s\n", buffer1);
printf(" 缓冲区2: %s\n", buffer2);
printf(" 缓冲区3: %s\n", buffer3);
}

close(fd);
}

// 资源限制示例
void demonstrate_resource_limits() {
printf("\n=== 资源限制示例 ===\n");

struct rlimit64 limit;

// 获取当前进程的文件大小限制
if (prlimit64(0, RLIMIT_FSIZE, NULL, &limit) == 0) {
printf("文件大小限制:\n");
printf(" 软限制: %lld\n", (long long)limit.rlim_cur);
printf(" 硬限制: %lld\n", (long long)limit.rlim_max);
}

// 获取内存限制
if (prlimit64(0, RLIMIT_AS, NULL, &limit) == 0) {
printf("虚拟内存限制:\n");
if (limit.rlim_cur == RLIM64_INFINITY) {
printf(" 软限制: 无限制\n");
} else {
printf(" 软限制: %lld 字节 (%.2f MB)\n",
(long long)limit.rlim_cur,
(double)limit.rlim_cur / (1024 * 1024));
}
if (limit.rlim_max == RLIM64_INFINITY) {
printf(" 硬限制: 无限制\n");
} else {
printf(" 硬限制: %lld 字节 (%.2f MB)\n",
(long long)limit.rlim_max,
(double)limit.rlim_max / (1024 * 1024));
}
}

// 获取打开文件数限制
if (prlimit64(0, RLIMIT_NOFILE, NULL, &limit) == 0) {
printf("文件描述符限制:\n");
printf(" 软限制: %lld\n", (long long)limit.rlim_cur);
printf(" 硬限制: %lld\n", (long long)limit.rlim_max);
}
}

int main() {
const char *test_file = "io_test_file.txt";

printf("=== Linux I/O 系统调用对比分析 ===\n");

// 创建测试文件
create_test_file(test_file);

// 基础 I/O 对比
compare_basic_io(test_file);

// 分散/聚集 I/O 示例
demonstrate_vector_io(test_file);

// 资源限制示例
demonstrate_resource_limits();

// 清理
unlink(test_file);

printf("\n=== 使用建议 ===\n");
printf("选择指南:\n");
printf("1. 简单读写: 使用 read/write\n");
printf("2. 需要指定位置: 使用 pread/pwrite\n");
printf("3. 多缓冲区操作: 使用 preadv/pwritev\n");
printf("4. 需要高级控制: 使用 preadv2/pwritev2\n");
printf("5. 资源限制管理: 使用 prlimit64\n");

return 0;
}

4.2 性能基准测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <time.h>
#include <string.h>

#define ITERATIONS 10000
#define BUFFER_SIZE 1024

// 性能测试结构体
struct performance_test {
const char *name;
double (*test_func)(int fd, const char *filename);
};

// read 性能测试
double test_read_performance(int fd, const char *filename) {
char buffer&#91;BUFFER_SIZE];
struct timespec start, end;

clock_gettime(CLOCK_MONOTONIC, &start);

for (int i = 0; i < ITERATIONS; i++) {
lseek(fd, 0, SEEK_SET); // 重置到文件开头
read(fd, buffer, sizeof(buffer));
}

clock_gettime(CLOCK_MONOTONIC, &end);

return (end.tv_sec - start.tv_sec) * 1000000.0 +
(end.tv_nsec - start.tv_nsec) / 1000.0; // 微秒
}

// pread 性能测试
double test_pread_performance(int fd, const char *filename) {
char buffer&#91;BUFFER_SIZE];
struct timespec start, end;

clock_gettime(CLOCK_MONOTONIC, &start);

for (int i = 0; i < ITERATIONS; i++) {
pread(fd, buffer, sizeof(buffer), 0); // 始终从位置0读取
}

clock_gettime(CLOCK_MONOTONIC, &end);

return (end.tv_sec - start.tv_sec) * 1000000.0 +
(end.tv_nsec - start.tv_nsec) / 1000.0; // 微秒
}

// readv 性能测试
double test_readv_performance(int fd, const char *filename) {
char buffer1&#91;256], buffer2&#91;256], buffer3&#91;256], buffer4&#91;256];
struct iovec iov&#91;4];
struct timespec start, end;

// 设置分散读取
iov&#91;0].iov_base = buffer1;
iov&#91;0].iov_len = sizeof(buffer1);
iov&#91;1].iov_base = buffer2;
iov&#91;1].iov_len = sizeof(buffer2);
iov&#91;2].iov_base = buffer3;
iov&#91;2].iov_len = sizeof(buffer3);
iov&#91;3].iov_base = buffer4;
iov&#91;3].iov_len = sizeof(buffer4);

clock_gettime(CLOCK_MONOTONIC, &start);

for (int i = 0; i < ITERATIONS; i++) {
lseek(fd, 0, SEEK_SET);
readv(fd, iov, 4);
}

clock_gettime(CLOCK_MONOTONIC, &end);

return (end.tv_sec - start.tv_sec) * 1000000.0 +
(end.tv_nsec - start.tv_nsec) / 1000.0; // 微秒
}

// preadv 性能测试
double test_preadv_performance(int fd, const char *filename) {
char buffer1&#91;256], buffer2&#91;256], buffer3&#91;256], buffer4&#91;256];
struct iovec iov&#91;4];
struct timespec start, end;

// 设置分散读取
iov&#91;0].iov_base = buffer1;
iov&#91;0].iov_len = sizeof(buffer1);
iov&#91;1].iov_base = buffer2;
iov&#91;1].iov_len = sizeof(buffer2);
iov&#91;2].iov_base = buffer3;
iov&#91;2].iov_len = sizeof(buffer3);
iov&#91;3].iov_base = buffer4;
iov&#91;3].iov_len = sizeof(buffer4);

clock_gettime(CLOCK_MONOTONIC, &start);

for (int i = 0; i < ITERATIONS; i++) {
preadv(fd, iov, 4, 0); // 始终从位置0读取
}

clock_gettime(CLOCK_MONOTONIC, &end);

return (end.tv_sec - start.tv_sec) * 1000000.0 +
(end.tv_nsec - start.tv_nsec) / 1000.0; // 微秒
}

void run_performance_benchmark() {
const char *test_file = "benchmark_test.dat";
int fd;

printf("=== I/O 性能基准测试 ===\n");

// 创建大测试文件
fd = open(test_file, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd != -1) {
char *buffer = malloc(1024 * 1024); // 1MB 缓冲区
if (buffer) {
for (int i = 0; i < 10; i++) { // 创建 10MB 文件
write(fd, buffer, 1024 * 1024);
}
free(buffer);
}
close(fd);
}

// 打开文件进行读取测试
fd = open(test_file, O_RDONLY);
if (fd == -1) {
perror("打开测试文件失败");
return;
}

struct performance_test tests&#91;] = {
{"read", test_read_performance},
{"pread", test_pread_performance},
{"readv", test_readv_performance},
{"preadv", test_preadv_performance},
{NULL, NULL}
};

printf("%-10s %-15s %-15s\n", "函数", "耗时(微秒)", "平均耗时(纳秒)");
printf("%-10s %-15s %-15s\n", "----", "----------", "--------------");

for (int i = 0; tests&#91;i].name; i++) {
double total_time = tests&#91;i].test_func(fd, test_file);
double avg_time = total_time * 1000.0 / ITERATIONS;

printf("%-10s %-15.2f %-15.2f\n",
tests&#91;i].name, total_time, avg_time);
}

close(fd);
unlink(test_file);

printf("\n性能分析:\n");
printf("1. pread 比 read 略慢 (位置指定开销)\n");
printf("2. readv/preadv 在多缓冲区场景下更高效\n");
printf("3. preadv2/pwritev2 提供更多控制选项\n");
printf("4. 选择应基于具体使用场景\n");
}

int main() {
printf("=== Linux I/O 系统调用完整对比分析 ===\n\n");

// 运行性能基准测试
run_performance_benchmark();

printf("\n=== 详细功能对比 ===\n");
printf("pread vs read:\n");
printf(" • pread: 指定位置读取,不改变文件位置\n");
printf(" • read: 顺序读取,会改变文件位置\n");
printf("\n");

printf("preadv vs pread:\n");
printf(" • preadv: 分散读取到多个缓冲区\n");
printf(" • pread: 读取到单个缓冲区\n");
printf("\n");

printf("preadv2 vs preadv:\n");
printf(" • preadv2: 支持额外标志控制\n");
printf(" • preadv: 基本的分散读取功能\n");
printf("\n");

printf("prlimit64:\n");
printf(" • 用于获取和设置进程资源限制\n");
printf(" • 支持 64 位资源限制值\n");
printf(" • 可以操作其他进程的资源限制\n");

printf("\n=== 实际应用建议 ===\n");
printf("1. 日志文件读写: 使用 pread/pwrite\n");
printf("2. 数据库存储引擎: 使用 preadv/pwritev\n");
printf("3. 高性能网络服务: 使用 preadv2/pwritev2\n");
printf("4. 系统资源管理: 使用 prlimit64\n");
printf("5. 简单文件操作: 使用 read/write\n");

return 0;
}

4.3 实际应用场景演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <string.h>
#include <errno.h>
#include <sys/resource.h>

// 日志文件读取示例
void log_file_reader_example() {
printf("=== 日志文件读取场景 ===\n");

// 创建模拟日志文件
const char *log_file = "application.log";
int fd = open(log_file, O_CREAT | O_WRONLY | O_TRUNC, 0644);

if (fd != -1) {
const char *log_entries&#91;] = {
"2023-01-01 10:00:00 INFO Application started\n",
"2023-01-01 10:00:01 DEBUG Loading configuration\n",
"2023-01-01 10:00:02 WARN Low memory warning\n",
"2023-01-01 10:00:03 ERROR Database connection failed\n",
"2023-01-01 10:00:04 INFO Recovery attempt started\n"
};

for (int i = 0; i < 5; i++) {
write(fd, log_entries&#91;i], strlen(log_entries&#91;i]));
}
close(fd);
}

// 使用 pread 读取特定时间段的日志
fd = open(log_file, O_RDONLY);
if (fd != -1) {
char buffer&#91;256];

printf("读取最后一条日志记录:\n");
// 从文件末尾附近读取
ssize_t bytes_read = pread(fd, buffer, sizeof(buffer) - 1, 150);
if (bytes_read > 0) {
buffer&#91;bytes_read] = '\0';
printf(" %s", buffer);
}

close(fd);
}

unlink(log_file);
}

// 数据库页读取示例
void database_page_reader_example() {
printf("\n=== 数据库页读取场景 ===\n");

const char *db_file = "database_pages.dat";
int fd = open(db_file, O_CREAT | O_WRONLY | O_TRUNC, 0644);

if (fd != -1) {
// 创建模拟的数据库页
char page_data&#91;4096];
for (int page = 0; page < 10; page++) {
snprintf(page_data, sizeof(page_data),
"Page %d: Database page content with ID=%d and timestamp=%ld\n",
page, page * 1000, time(NULL));
write(fd, page_data, strlen(page_data));
}
close(fd);
}

// 使用 preadv 读取多个数据库页
fd = open(db_file, O_RDONLY);
if (fd != -1) {
char page1&#91;1024], page2&#91;1024], page3&#91;1024];
struct iovec iov&#91;3];

// 设置分散读取
iov&#91;0].iov_base = page1;
iov&#91;0].iov_len = sizeof(page1) - 1;

iov&#91;1].iov_base = page2;
iov&#91;1].iov_len = sizeof(page2) - 1;

iov&#91;2].iov_base = page3;
iov&#91;2].iov_len = sizeof(page3) - 1;

printf("使用 preadv 读取多个数据库页:\n");
ssize_t total_bytes = preadv(fd, iov, 3, 0); // 从开头读取
printf(" 总共读取: %zd 字节\n", total_bytes);

if (total_bytes > 0) {
page1&#91;iov&#91;0].iov_len] = '\0';
page2&#91;iov&#91;1].iov_len] = '\0';
page3&#91;iov&#91;2].iov_len] = '\0';

printf(" 页1: %.50s...\n", page1);
printf(" 页2: %.50s...\n", page2);
printf(" 页3: %.50s...\n", page3);
}

close(fd);
}

unlink(db_file);
}

// 网络数据包处理示例
void network_packet_processor_example() {
printf("\n=== 网络数据包处理场景 ===\n");

// 模拟网络数据包结构
struct packet_header {
uint32_t magic;
uint16_t version;
uint16_t type;
uint32_t length;
uint32_t checksum;
} __attribute__((packed));

struct packet_payload {
char data&#91;1024];
};

// 创建测试数据包文件
const char *packet_file = "network_packets.dat";
int fd = open(packet_file, O_CREAT | O_WRONLY | O_TRUNC, 0644);

if (fd != -1) {
// 写入多个数据包
for (int i = 0; i < 3; i++) {
struct packet_header header = {
.magic = 0x12345678,
.version = 1,
.type = i,
.length = 100,
.checksum = 0xABCDEF00 + i
};

char payload&#91;1024];
snprintf(payload, sizeof(payload),
"Packet %d payload data with timestamp %ld",
i, time(NULL));

write(fd, &header, sizeof(header));
write(fd, payload, strlen(payload) + 1);
}
close(fd);
}

// 使用 preadv2 读取数据包(如果支持)
fd = open(packet_file, O_RDONLY);
if (fd != -1) {
struct packet_header headers&#91;3];
char payloads&#91;3]&#91;256];
struct iovec iov&#91;6]; // 3个头部 + 3个载荷

// 设置分散读取结构
for (int i = 0; i < 3; i++) {
iov&#91;i*2].iov_base = &headers&#91;i];
iov&#91;i*2].iov_len = sizeof(struct packet_header);

iov&#91;i*2+1].iov_base = payloads&#91;i];
iov&#91;i*2+1].iov_len = sizeof(payloads&#91;i]) - 1;
}

printf("使用分散读取处理网络数据包:\n");
ssize_t bytes_read = preadv(fd, iov, 6, 0);
printf(" 读取字节数: %zd\n", bytes_read);

if (bytes_read > 0) {
for (int i = 0; i < 3; i++) {
printf(" 数据包 %d:\n", i);
printf(" 魔数: 0x%08X\n", headers&#91;i].magic);
printf(" 版本: %d\n", headers&#91;i].version);
printf(" 类型: %d\n", headers&#91;i].type);
printf(" 长度: %d\n", headers&#91;i].length);
printf(" 校验: 0x%08X\n", headers&#91;i].checksum);
payloads&#91;i]&#91;iov&#91;i*2+1].iov_len] = '\0';
printf(" 载荷: %.50s...\n", payloads&#91;i]);
printf("\n");
}
}

close(fd);
}

unlink(packet_file);
}

// 资源限制管理示例
void resource_limit_management_example() {
printf("\n=== 资源限制管理场景 ===\n");

struct rlimit64 old_limit, new_limit;

// 获取当前文件大小限制
if (prlimit64(0, RLIMIT_FSIZE, NULL, &old_limit) == 0) {
printf("当前文件大小限制:\n");
if (old_limit.rlim_cur == RLIM64_INFINITY) {
printf(" 软限制: 无限制\n");
} else {
printf(" 软限制: %lld 字节 (%.2f GB)\n",
(long long)old_limit.rlim_cur,
(double)old_limit.rlim_cur / (1024 * 1024 * 1024));
}
}

// 获取打开文件数限制
if (prlimit64(0, RLIMIT_NOFILE, NULL, &old_limit) == 0) {
printf("当前文件描述符限制:\n");
printf(" 软限制: %lld\n", (long long)old_limit.rlim_cur);
printf(" 硬限制: %lld\n", (long long)old_limit.rlim_max);
}

// 获取内存限制
if (prlimit64(0, RLIMIT_AS, NULL, &old_limit) == 0) {
printf("当前虚拟内存限制:\n");
if (old_limit.rlim_cur == RLIM64_INFINITY) {
printf(" 软限制: 无限制\n");
} else {
printf(" 软限制: %lld 字节 (%.2f GB)\n",
(long long)old_limit.rlim_cur,
(double)old_limit.rlim_cur / (1024 * 1024 * 1024));
}
}

printf("\n资源限制管理最佳实践:\n");
printf("1. 合理设置文件大小限制防止磁盘填满\n");
printf("2. 适当增加文件描述符限制支持高并发\n");
printf("3. 监控内存使用防止内存泄漏\n");
printf("4. 使用 prlimit64 动态调整资源限制\n");
}

int main() {
printf("=== Linux I/O 系统调用应用场景演示 ===\n\n");

// 日志文件读取场景
log_file_reader_example();

// 数据库页读取场景
database_page_reader_example();

// 网络数据包处理场景
network_packet_processor_example();

// 资源限制管理场景
resource_limit_management_example();

printf("\n=== 总结 ===\n");
printf("I/O 系统调用选择指南:\n");
printf("\n");
printf("┌─────────────┬────────────────────────────────────┐\n");
printf("│ 场景 │ 推荐函数 │\n");
printf("├─────────────┼────────────────────────────────────┤\n");
printf("│ 简单读写 │ read/write │\n");
printf("│ 位置指定 │ pread/pwrite │\n");
printf("│ 多缓冲区 │ readv/writev │\n");
printf("│ 位置+多缓冲 │ preadv/pwritev │\n");
printf("│ 高级控制 │ preadv2/pwritev2 │\n");
printf("│ 资源限制 │ prlimit64 │\n");
printf("└─────────────┴────────────────────────────────────┘\n");
printf("\n");
printf("性能优化建议:\n");
printf("1. 批量操作减少系统调用次数\n");
printf("2. 合理选择缓冲区大小\n");
printf("3. 使用位置指定避免文件位置移动\n");
printf("4. 分散/聚集 I/O 减少内存拷贝\n");
printf("5. 合理设置资源限制防止系统过载\n");

return 0;
}

  1. 编译和运行说明
1
2
3
4
5
6
7
8
9
10
# 编译示例程序
gcc -o io_comparison_example1 example1.c
gcc -o io_comparison_example2 example2.c
gcc -o io_comparison_example3 example3.c

# 运行示例
./io_comparison_example1
./io_comparison_example2
./io_comparison_example3

  1. 系统要求检查
1
2
3
4
5
6
7
8
9
10
11
12
# 检查内核版本
uname -r

# 检查 glibc 版本
ldd --version

# 检查系统调用支持
grep -E "(pread|pwrite|prlimit)" /usr/include/asm/unistd_64.h

# 查看文件系统性能
hdparm -Tt /dev/sda # 硬盘性能测试

  1. 重要注意事项

原子性: pread/pwrite 操作是原子的

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

位置独立: 不改变文件描述符的当前位置

错误处理: 始终检查返回值和 errno

内存对齐: 在某些架构上有对齐要求

权限检查: 确保有足够的权限进行操作

资源清理: 及时关闭文件描述符

  1. 最佳实践总结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 安全的 I/O 操作封装
ssize_t safe_pread(int fd, void *buf, size_t count, off_t offset) {
if (fd < 0 || !buf || count == 0) {
errno = EINVAL;
return -1;
}

ssize_t result;
do {
result = pread(fd, buf, count, offset);
} while (result == -1 && errno == EINTR);

return result;
}

// 安全的分散读取封装
ssize_t safe_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
if (fd < 0 || !iov || iovcnt <= 0 || iovcnt > IOV_MAX) {
errno = EINVAL;
return -1;
}

ssize_t result;
do {
result = preadv(fd, iov, iovcnt, offset);
} while (result == -1 && errno == EINTR);

return result;
}

// 资源限制检查
int check_resource_limits() {
struct rlimit64 limit;

// 检查文件大小限制
if (prlimit64(0, RLIMIT_FSIZE, NULL, &limit) == 0) {
if (limit.rlim_cur != RLIM64_INFINITY && limit.rlim_cur < 1024 * 1024) {
printf("警告: 文件大小限制过小 (%lld 字节)\n",
(long long)limit.rlim_cur);
}
}

// 检查文件描述符限制
if (prlimit64(0, RLIMIT_NOFILE, NULL, &limit) == 0) {
if (limit.rlim_cur < 1024) {
printf("警告: 文件描述符限制过小 (%lld)\n",
(long long)limit.rlim_cur);
}
}

return 0;
}

这些示例全面展示了 Linux I/O 系统调用的功能特点、使用方法和实际应用场景,帮助开发者根据具体需求选择合适的 I/O 操作方式。

data-ad-format="auto" data-full-width-responsive="true">