linux下io操作详细解析

在 Linux 系统下,IO(输入/输出)操作是程序与外部设备(如文件、网络等)交互的重要方式。Linux 提供了丰富的系统调用和库函数来支持各种 IO 操作。以下是对 Linux 下 IO 操作的详细解析,包括文件 IO、网络 IO 和缓冲机制等内容。


一、文件 IO 操作

1. 打开文件(open 系统调用)

open 系统调用用于打开一个文件,返回一个文件描述符(file descriptor),后续操作都通过这个文件描述符进行。

cpp 复制代码
#include <fcntl.h>
#include <unistd.h>
#include <iostream>

int main() {
    int fd = open("example.txt", O_RDONLY); // 打开文件用于只读
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    std::cout << "File opened successfully, file descriptor: " << fd << std::endl;
    close(fd); // 关闭文件
    return 0;
}
  • O_RDONLY:只读模式。

  • O_WRONLY:只写模式。

  • O_RDWR:读写模式。

  • O_CREAT:如果文件不存在,则创建文件。

  • O_TRUNC:如果文件已存在,将其长度截断为 0。

  • O_APPEND:写入时将数据追加到文件末尾。

2. 读取文件(read 系统调用)

read 系统调用从文件描述符指定的文件中读取数据。

cpp 复制代码
#include <fcntl.h>
#include <unistd.h>
#include <iostream>

int main() {
    int fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    char buffer[128];
    ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);
    if (bytesRead == -1) {
        perror("read failed");
        close(fd);
        return 1;
    }

    buffer[bytesRead] = '\0'; // 确保字符串以 null 结尾
    std::cout << "Read " << bytesRead << " bytes: " << buffer << std::endl;

    close(fd);
    return 0;
}
  • read 返回读取的字节数,如果返回 0 表示已到达文件末尾,返回 -1 表示出错。

3. 写入文件(write 系统调用)

write 系统调用将数据写入到文件描述符指定的文件中。

cpp 复制代码
#include <fcntl.h>
#include <unistd.h>
#include <iostream>

int main() {
    int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    const char* msg = "Hello, world!";
    ssize_t bytesWritten = write(fd, msg, strlen(msg));
    if (bytesWritten == -1) {
        perror("write failed");
        close(fd);
        return 1;
    }

    std::cout << "Wrote " << bytesWritten << " bytes." << std::endl;

    close(fd);
    return 0;
}
  • O_CREAT:如果文件不存在,则创建文件。

  • 0644:文件权限,表示所有者有读写权限,组用户和其他用户有读权限。

4. 关闭文件(close 系统调用)

close 系统调用用于关闭文件描述符,释放资源。

复制代码
close(fd);

二、网络 IO 操作

1. 创建套接字(socket 系统调用)

socket 系统调用用于创建一个套接字,用于网络通信。

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>
#include <iostream>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建 TCP 套接字
    if (sockfd == -1) {
        perror("socket failed");
        return 1;
    }

    std::cout << "Socket created successfully, file descriptor: " << sockfd << std::endl;
    close(sockfd);
    return 0;
}
  • AF_INET:IPv4 地址族。

  • SOCK_STREAM:TCP 套接字。

  • SOCK_DGRAM:UDP 套接字。

2. 绑定地址(bind 系统调用)

bind 系统调用将套接字绑定到一个本地地址和端口。

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket failed");
        return 1;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080); // 端口号
    addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有可用地址

    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        perror("bind failed");
        close(sockfd);
        return 1;
    }

    std::cout << "Socket bound to port 8080." << std::endl;
    close(sockfd);
    return 0;
}

3. 监听连接(listen 系统调用)

listen 系统调用将套接字设置为监听状态,等待客户端连接。

cpp 复制代码
if (listen(sockfd, 5) == -1) { // 最大连接队列长度为 5
    perror("listen failed");
    close(sockfd);
    return 1;
}

std::cout << "Server is listening on port 8080." << std::endl;

4. 接受连接(accept 系统调用)

accept 系统调用接受一个客户端连接,返回一个新的套接字用于与客户端通信。

cpp 复制代码
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);

int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
if (clientfd == -1) {
    perror("accept failed");
    close(sockfd);
    return 1;
}

std::cout << "Client connected." << std::endl;

5. 读写网络数据

使用 readwrite 系统调用(或 recvsend 函数)进行网络数据的读写。

cpp 复制代码
char buffer[1024];
ssize_t bytesRead = read(clientfd, buffer, sizeof(buffer) - 1);
if (bytesRead == -1) {
    perror("read failed");
    close(clientfd);
    close(sockfd);
    return 1;
}

buffer[bytesRead] = '\0';
std::cout << "Received message: " << buffer << std::endl;

const char* response = "Hello, client!";
write(clientfd, response, strlen(response));

三、缓冲机制

1. 标准 IO 缓冲

C 标准库提供了缓冲机制,通过 FILE* 指针操作文件。例如:

cpp 复制代码
#include <cstdio>
#include <iostream>

int main() {
    FILE* file = fopen("example.txt", "r");
    if (!file) {
        perror("fopen failed");
        return 1;
    }

    char buffer[128];
    while (fgets(buffer, sizeof(buffer), file)) {
        std::cout << buffer;
    }

    fclose(file);
    return 0;
}
  • fgets 从文件中读取一行,自动处理缓冲。

  • fputs 将字符串写入文件,也使用缓冲机制。

2. 系统调用与缓冲

系统调用(如 readwrite)通常不使用缓冲,直接与内核交互。如果需要缓冲,可以手动实现,例如:

cpp 复制代码
char buffer[1024];
ssize_t bytesRead = read(fd, buffer, sizeof(buffer));

3. 非阻塞 IO 和异步 IO

  • 非阻塞 IO :通过设置文件描述符为非阻塞模式,使 readwrite 在数据未准备好时立即返回

    cpp 复制代码
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
  • 异步 IO :使用 aioio_uring 等机制,允许程序在 IO 操作完成之前继续执行。

相关推荐
空名_Noname8 分钟前
三维点云投影二维图像的原理及实现
c++·点云·pointcloud
步行cgn9 分钟前
TreeMap 核心知识点与面试题解析
java·开发语言·面试
tt55555555555513 分钟前
python文件打包无法导入ultralytics模块
开发语言·pytorch·笔记·python
刚入门的大一新生19 分钟前
C++初阶-类和对象(上)
开发语言·c++
虾球xz20 分钟前
游戏引擎学习第219天
c++·学习·游戏引擎
柒_汐24 分钟前
第十五届蓝桥杯C/C++B组省赛真题讲解(分享去年比赛的一些真实感受)
c语言·c++·蓝桥杯·真题·省赛
遇见你的雩风25 分钟前
Java---抽象类与接口
java·开发语言
qq_214782611 小时前
Python Orange:托拉拽玩转机器学习、数据挖掘!
开发语言·python·数据分析
huofengfeihu1 小时前
【c】-include经典注入问题
c语言·开发语言
nuo5342021 小时前
第十六届蓝桥杯 省赛C/C++ 大学B组
c语言·c++·算法·蓝桥杯·图论