Linux中POSIX应用场景

news/2025/2/21 23:41:47

Linux 提供了丰富的 POSIX(Portable Operating System Interface)标准接口,这些接口可以帮助开发者编写可移植、高效的应用程序。POSIX 标准定义了一系列系统调用和库函数,涵盖了文件操作、进程管理、线程管理、信号处理、同步机制等方面。

1. 文件操作

POSIX 提供了标准的文件操作接口,用于文件的创建、读取、写入、关闭等操作。

  • open(): 打开文件。
  • close(): 关闭文件。
  • read(): 从文件中读取数据。
  • write(): 向文件中写入数据。
  • lseek(): 移动文件指针。
#include <fcntl.h>   // 包含文件控制相关的函数和宏定义,如 open()
#include <unistd.h>  // 包含 POSIX 标准的系统调用,如 read(), write(), close(), lseek()
#include <iostream>  // 包含标准输入输出流,如 std::cout

int main() {
    // 打开文件 "example.txt",如果文件不存在则创建它
    // O_RDWR: 以读写模式打开文件
    // O_CREAT: 如果文件不存在则创建
    // 0644: 文件权限设置为用户可读写,组和其他用户只读
    int fd = open("example.txt", O_RDWR | O_CREAT, 0644);
    if (fd == -1) {  // 检查文件是否成功打开
        perror("open");  // 如果失败,打印错误信息
        return 1;        // 返回错误码 1
    }

    // 要写入文件的字符串
    const char *text = "Hello, POSIX!";
    // 将字符串写入文件
    // fd: 文件描述符
    // text: 要写入的数据
    // 13: 写入的字节数(字符串长度)
    write(fd, text, 13);

    // 将文件指针移动到文件开头
    // fd: 文件描述符
    // 0: 偏移量
    // SEEK_SET: 从文件开头开始计算偏移量
    lseek(fd, 0, SEEK_SET);

    // 定义一个缓冲区,用于存储从文件中读取的数据
    char buffer[14];
    // 从文件中读取数据到缓冲区
    // fd: 文件描述符
    // buffer: 存储读取数据的缓冲区
    // 13: 读取的字节数
    read(fd, buffer, 13);
    buffer[13] = '\0';  // 在缓冲区末尾添加字符串结束符

    // 将读取的数据打印到标准输出
    std::cout << buffer << std::endl;

    // 关闭文件
    close(fd);

    return 0;  // 程序正常结束
}

2. 进程管理

POSIX 提供了进程创建、终止、等待等接口。

  • fork(): 创建子进程。
  • exec() 系列函数: 执行新程序。
  • wait()waitpid(): 等待子进程结束。
  • exit(): 终止进程。
#include <unistd.h>   // 包含 POSIX 标准的系统调用,如 fork(), execlp()
#include <sys/wait.h> // 包含进程等待相关的函数,如 wait()
#include <iostream>   // 包含标准输入输出流,如 std::cout

int main() {
    // 创建一个子进程
    // fork() 返回两次:
    // - 在父进程中返回子进程的 PID
    // - 在子进程中返回 0
    // - 如果失败,返回 -1
    pid_t pid = fork();//父进程和子进程会从 fork() 之后开始并行执行。

    if (pid == 0) {
        // 子进程
        // 使用 execlp() 执行 "ls -l" 命令
        // execlp() 会用指定的程序替换当前进程的地址空间
        // "ls": 要执行的程序(在 PATH 中查找)
        // "ls": 传递给程序的第一个参数(通常是程序名)
        // "-l": 传递给程序的第二个参数(长格式显示)
        // nullptr: 参数列表的结束标志
        execlp("ls", "ls", "-l", nullptr);

        // 如果 execlp() 执行成功,以下代码不会被执行
        // 如果执行失败,会继续执行并打印错误信息
        perror("execlp");
        return 1; // 子进程异常退出
    } else if (pid > 0) {
        // 父进程
        // 等待子进程结束
        // wait() 会阻塞父进程,直到子进程退出
        // nullptr 表示不关心子进程的退出状态
        wait(nullptr);

        // 子进程结束后,打印提示信息
        std::cout << "Child process finished." << std::endl;
    } else {
        // fork() 失败
        perror("fork"); // 打印错误信息
        return 1;       // 返回错误码 1
    }

    return 0; // 程序正常结束
}

3. 线程管理

POSIX 线程(Pthreads)提供了多线程编程的接口。

  • pthread_create(): 创建线程。
  • pthread_join(): 等待线程结束。
  • pthread_exit(): 终止线程。
#include <pthread.h> // 包含 POSIX 线程相关的函数和数据类型,如 pthread_create(), pthread_join()
#include <iostream>  // 包含标准输入输出流,如 std::cout

// 线程函数,新线程启动后执行的函数
void* thread_func(void* arg) {
    // 打印线程中的消息
    std::cout << "Hello from thread!" << std::endl;
    return nullptr; // 线程函数返回 nullptr,表示没有返回值
}

int main() {
    pthread_t thread; // 定义一个线程标识符

    // 创建一个新线程
    // &thread: 用于存储新线程的标识符
    // nullptr: 使用默认的线程属性
    // thread_func: 线程启动后执行的函数
    // nullptr: 传递给线程函数的参数(这里没有传递参数)
    if (pthread_create(&thread, nullptr, thread_func, nullptr) != 0) {
        // 如果线程创建失败,打印错误信息并退出
        perror("pthread_create");
        return 1; // 返回错误码 1
    }

    // 等待线程结束
    // thread: 要等待的线程标识符
    // nullptr: 不关心线程的返回值
    pthread_join(thread, nullptr);

    // 线程结束后,打印提示信息
    std::cout << "Thread finished." << std::endl;

    return 0; // 程序正常结束
}

4. 信号处理

POSIX 提供了信号处理机制,用于处理异步事件。

  • signal(): 设置信号处理函数。
  • sigaction(): 更复杂的信号处理设置。
  • kill(): 发送信号给进程。
#include <csignal>   // 包含信号处理相关的函数和常量,如 signal(), SIGINT
#include <unistd.h>  // 包含 POSIX 标准的系统调用,如 sleep()
#include <iostream>  // 包含标准输入输出流,如 std::cout

// 信号处理函数
void signal_handler(int signum) {
    // 输出接收到的信号编号
    std::cout << "Received signal " << signum << std::endl;
}

int main() {
    // 注册信号处理函数
    // 将 SIGINT 信号(通常是 Ctrl+C 触发的信号)与 signal_handler 函数绑定
    signal(SIGINT, signal_handler);

    // 无限循环,等待信号
    while (true) {
        std::cout << "Waiting for signal..." << std::endl;
        sleep(1); // 休眠 1 秒
    }

    return 0; // 程序正常结束(实际上不会执行到这里)
}

5. 同步机制

POSIX 提供了多种同步机制,如互斥锁、条件变量、信号量等。

  • pthread_mutex_t: 互斥锁。
  • pthread_cond_t: 条件变量。
  • sem_t: 信号量。
#include <pthread.h> // 包含 POSIX 线程相关的函数和数据类型,如 pthread_create(), pthread_mutex_t
#include <iostream>  // 包含标准输入输出流,如 std::cout

// 定义互斥锁
pthread_mutex_t mutex;

// 定义共享数据
int shared_data = 0;

// 线程函数
void* thread_func(void* arg) {
    // 加锁,确保对共享数据的访问是互斥的
    pthread_mutex_lock(&mutex);

    // 修改共享数据
    shared_data++;

    // 输出共享数据的值
    std::cout << "Shared data: " << shared_data << std::endl;

    // 解锁,允许其他线程访问共享数据
    pthread_mutex_unlock(&mutex);

    // 返回空指针
    return nullptr;
}

int main() {
    // 定义两个线程标识符
    pthread_t thread1, thread2;

    // 初始化互斥锁
    // 第二个参数是互斥锁属性,这里使用默认属性,传入 nullptr
    pthread_mutex_init(&mutex, nullptr);

    // 创建第一个线程
    // pthread_create() 参数:
    // 1. 线程标识符
    // 2. 线程属性(默认属性,传入 nullptr)
    // 3. 线程函数
    // 4. 传递给线程函数的参数(这里不需要,传入 nullptr)
    pthread_create(&thread1, nullptr, thread_func, nullptr);

    // 创建第二个线程
    pthread_create(&thread2, nullptr, thread_func, nullptr);

    // 等待第一个线程结束
    // pthread_join() 会阻塞,直到指定线程结束
    // 第二个参数用于获取线程的返回值,这里不需要,传入 nullptr
    pthread_join(thread1, nullptr);

    // 等待第二个线程结束
    pthread_join(thread2, nullptr);

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0; // 程序正常结束
}

6. 时间管理

POSIX 提供了时间相关的函数,用于获取和操作时间。

  • gettimeofday(): 获取当前时间。
  • clock_gettime(): 获取更高精度的时间。
  • sleep(): 让进程休眠指定时间。
#include <sys/time.h> // 包含时间相关的函数和数据结构,如 gettimeofday()
#include <unistd.h>   // 包含 POSIX 标准的系统调用,如 sleep()
#include <iostream>   // 包含标准输入输出流,如 std::cout

int main() {
    // 定义两个 timeval 结构体,用于存储时间点
    struct timeval start, end;

    // 获取当前时间,并存储到 start 中
    // gettimeofday() 获取从 1970-01-01 00:00:00 UTC 到当前时间的秒数和微秒数
    // 第二个参数是时区信息,这里不需要,传入 nullptr
    gettimeofday(&start, nullptr);

    // 让程序休眠 2 秒
    sleep(2);

    // 获取当前时间,并存储到 end 中
    gettimeofday(&end, nullptr);

    // 计算时间差
    long seconds = end.tv_sec - start.tv_sec;       // 计算秒数差
    long microseconds = end.tv_usec - start.tv_usec; // 计算微秒数差

    // 将时间差转换为秒(包括微秒部分)
    double elapsed = seconds + microseconds / 1e6; // 1e6 表示 1,000,000,将微秒转换为秒

    // 输出耗时
    std::cout << "Elapsed time: " << elapsed << " seconds" << std::endl;

    return 0; // 程序正常结束
}

7. 网络编程

POSIX 提供了套接字(socket)接口,用于网络编程。

  • socket(): 创建套接字。
  • bind(): 绑定套接字到地址。
  • listen(): 监听连接。
  • accept(): 接受连接。
  • connect(): 连接到服务器
  • send()recv(): 发送和接收数据。
#include <sys/socket.h> // 包含套接字相关的函数和数据结构,如 socket(), bind(), listen(), accept()
#include <netinet/in.h> // 包含 IPv4 地址结构体 sockaddr_in 和相关的常量,如 INADDR_ANY
#include <unistd.h>     // 包含 POSIX 标准的系统调用,如 close()
#include <iostream>     // 包含标准输入输出流,如 std::cout
#include <cstring>      // 包含字符串操作函数,如 strlen()

int main() {
    // 创建一个套接字
    // AF_INET: 使用 IPv4 地址族
    // SOCK_STREAM: 使用面向连接的 TCP 协议
    // 0: 默认协议(TCP)
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        // 如果套接字创建失败,打印错误信息并退出
        perror("socket");
        return 1; // 返回错误码 1
    }

    // 定义服务器地址结构
    struct sockaddr_in address;
    address.sin_family = AF_INET;           // 使用 IPv4 地址族
    address.sin_addr.s_addr = INADDR_ANY;   // 绑定到所有可用的网络接口
    address.sin_port = htons(8080);         // 绑定到端口 8080,htons() 将端口号转换为网络字节序

    // 将套接字绑定到指定的地址和端口
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        // 如果绑定失败,打印错误信息并退出
        perror("bind");
        return 1; // 返回错误码 1
    }

    // 开始监听连接请求
    // 3: 最大等待连接队列的长度
    if (listen(server_fd, 3) < 0) {
        // 如果监听失败,打印错误信息并退出
        perror("listen");
        return 1; // 返回错误码 1
    }

    // 接受客户端的连接请求
    // 返回一个新的套接字,用于与客户端通信
    // 后两个参数用于获取客户端的地址信息,这里不需要,因此传入 nullptr
    int new_socket = accept(server_fd, nullptr, nullptr);
    if (new_socket < 0) {
        // 如果接受连接失败,打印错误信息并退出
        perror("accept");
        return 1; // 返回错误码 1
    }

    // 向客户端发送消息
    const char *message = "Hello from server!";
    send(new_socket, message, strlen(message), 0);

    // 关闭与客户端的连接
    close(new_socket);

    // 关闭服务器套接字
    close(server_fd);

    return 0; // 程序正常结束
}

http://www.niftyadmin.cn/n/5861423.html

相关文章

[Android]文本多的时候让TextView的字体自动变小

为了让 TextView 的字体在文本过多时自动变小&#xff0c;以显示全部文本&#xff0c;可以使用 Android 的 autoSizeTextType 属性。该属性允许 TextView 在空间不足时自动调整字体大小。 在 XML 中&#xff0c;可以这样设置&#xff1a; <TextViewandroid:id"id/tv_…

使用 Spring Boot 和 Canal 实现 MySQL 数据库同步

文章目录 前言一、背景二、Canal 简介三、主库数据库配置1.主库配置2.创建 Canal 用户并授予权限 四.配置 Canal Server1.Canal Server 配置文件2.启动 Canal Server 五.开发 Spring Boot 客户端1. 引入依赖2. 配置 Canal 客户端3. 实现数据同步逻辑 六.启动并测试七.注意事项八…

uniapp 使用unplugin-auto-import 后, vue文件报红问题

现象 vite.config.js中已配置好unplugin-auto-import 解决方法 让你的auto-imports.d.ts文件, 处于打开状态 尼…玛…,的 这谁敢信 重新打开编译器后还会有这个问题 关掉auto-imports.d.ts文件, 重新打开 吐槽 我真$%$$#$%^&^%&^%^服了 各种改vite-config.js和ts…

使用Geotools读取DEM地形数据实战-以湖南省30米数据为例

目录 前言 一、DEM地形数据介绍 1、DEM数据简介 2、DEM应用领域 3、QGIS中读取DEM数据 二、GeoTools解析地形 1、Maven中依赖引用 2、获取数据基本信息 三、总结 前言 随着全球数字化进程的加速&#xff0c;各类地理空间数据呈爆炸式增长&#xff0c;DEM 数据作为其中的…

前后端项目部署服务器(传统部署和Docker部署)

内外网 开发环境连外网&#xff08;8.140.26.187&#xff09;&#xff0c;测试/生产环境连内网&#xff08;172.20.59.17&#xff09; 内外网地址不同&#xff0c;但指定的库是同一个 内网IP地址范围包括&#xff1a; 10.0.0.0 到 10.255.255.255172.16.0.0 到 172.31.2551…

【VUE面试】Vue2和Vue3的diff算法中,key的作用分别是什么?

在 Vue2 和 Vue3 的 Diff 算法里&#xff0c;key 都起着关键作用&#xff0c;但由于两个版本的 Diff 算法实现有所不同&#xff0c;key 的具体作用和使用场景也存在一些差异。以下详细介绍&#xff1a; Vue2 中 key 的作用 1. 辅助节点复用 在 Vue2 的 Diff 算法中&#xff0…

Spring IoC DI

一、IoC详解 控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09;是一种软件设计原则&#xff0c;其核心思想是将程序中的对象创建、依赖管理和生命周期控制的权力从应用程序代码转移到外部容器或框架&#xff0c;从而降低组件间的耦合度&#xff0c;提升代码…

ok113i平台——多媒体播放器适配

1. 视频播放支持 1.1 在Linux平台交叉编译ffmpeg动态库&#xff0c;详情查看《ok113i平台——交叉编译音视频动态库》 提取如下动态库&#xff1a; libavcodec.so.58.134.100 libavdevice.so.58.13.100 libavfilter.so.7.110.100 libavformat.so.58.76.100 libavutil.so.56.…