Linux系统重要(概念/模块)汇总

发布于:2024-12-18 ⋅ 阅读:(365) ⋅ 点赞:(0)

Linux的文件系统目录用途如下:
在这里插入图片描述

系统调用

在Linux中,应用程序通过系统调用来与硬件交互吗。

在 Ubuntu 或其他基于 Linux 的操作系统中,系统调用的数量并不是固定的,因为它们可能会随着内核版本的更新而变化。系统调用是用户空间程序与内核之间的接口,允许程序请求内核执行特权操作,如文件操作、进程管理、网络通信等。

截至 Linux 内核 5.x 版本,系统调用的数量大约在 300 到 400 之间,具体数量取决于内核的版本和配置。常见的系统调用包括:

  • 文件操作:openreadwritecloselseek
  • 进程管理:forkexecvewaitexit
  • 内存管理:mmapmunmapbrk
  • 网络操作:socketbindlistenacceptconnect

要查看当前系统支持的系统调用,可以使用 man 2 syscalls 命令,或者查阅相关的 Linux 内核文档。不同的 Linux 发行版可能会有不同的系统调用集,但大多数系统调用在不同的发行版中是相似的。

简单实例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>  // 包含 read、write、close 的声明
#include <fcntl.h>   // 包含 open 的声明
#include <string.h>

int main() {
    const char *filename = "example.txt";
    const char *text = "Hello, Linux System Calls!\n";
    char buffer[100];
    ssize_t bytesRead;

    // 创建并打开文件
    int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        perror("Error opening file");
        return EXIT_FAILURE;
    }

    // 写入文本到文件
    if (write(fd, text, strlen(text)) == -1) {
        perror("Error writing to file");
        close(fd);
        return EXIT_FAILURE;
    }

    // 关闭文件
    close(fd);

    // 重新打开文件以读取内容
    fd = open(filename, O_RDONLY);
    if (fd == -1) {
        perror("Error opening file for reading");
        return EXIT_FAILURE;
    }

    // 读取文件内容
    bytesRead = read(fd, buffer, sizeof(buffer) - 1);
    if (bytesRead == -1) {
        perror("Error reading from file");
        close(fd);
        return EXIT_FAILURE;
    }

    // 确保字符串以 null 结尾
    buffer[bytesRead] = '\0';

    // 打印读取的内容
    printf("Read from file: %s", buffer);

    // 关闭文件
    close(fd);

    return EXIT_SUCCESS;
}
open 系统调用用于创建或打开文件。这里使用了 O_CREAT、O_WRONLY 和 O_TRUNC 标志来创建一个新文件并准备写入。
write 系统调用用于将文本写入文件。
close 系统调用用于关闭文件描述符。
然后,程序重新打开文件以读取内容,使用 read 系统调用读取文件中的数据。
最后,程序打印读取的内容并关闭文件。

这个示例展示了如何通过系统调用与文件系统进行交互,进而与硬件(存储设备)进行间接交互。

网络程序实例

  • TCP服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};

    // 创建 socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket failed");
        exit(EXIT_FAILURE);
    }

    // 绑定 socket
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Server is listening on port %d\n", PORT);

    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("Accept failed");
        exit(EXIT_FAILURE);
    }

    // 读取客户端消息
    int bytes_read = read(new_socket, buffer, BUFFER_SIZE);
    if (bytes_read < 0) {
        perror("Read failed");
        exit(EXIT_FAILURE);
    }

    printf("Received message: %s\n", buffer);

    // 关闭 socket
    close(new_socket);
    close(server_fd);

    return 0;
}
  • TCP客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *message = "Hello, Server!";
    
    // 创建 socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 将 IPv4 地址从文本转换为二进制形式
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }

    // 发送消息
    send(sock, message, strlen(message), 0);
    printf("Message sent\n");

    // 关闭 socket
    close(sock);

    return 0;
}

Linux内核含义

可以理解为Linux内核就是实现了全部的系统调用吗?

是的,可以这样理解:Linux 内核实现了所有的系统调用。系统调用是用户空间程序与内核之间的接口,允许用户程序请求内核执行特权操作。内核负责处理这些请求,并提供相应的功能。

具体说明

  1. 系统调用的定义:系统调用是用户程序通过特定的接口请求内核执行操作的机制。这些操作通常涉及对硬件资源的访问或管理,例如文件操作、进程管理、内存管理和网络通信等。

  2. 内核的角色:Linux 内核是操作系统的核心部分,负责管理系统资源、提供硬件抽象、执行进程调度、处理系统调用等。内核实现了所有的系统调用,并提供了相应的功能。

  3. 系统调用的实现:当用户程序调用一个系统调用时,程序会通过特定的指令(如 int 0x80syscall)切换到内核模式。内核会根据系统调用的编号找到相应的处理函数,并执行该函数。执行完成后,内核会将结果返回给用户程序。

  4. 系统调用的种类:Linux 内核提供了多种系统调用,涵盖了文件操作、进程管理、内存管理、网络通信等多个方面。常见的系统调用包括 openreadwriteforkexecvesocket 等。

总结

因此,Linux 内核确实实现了所有的系统调用,并通过这些系统调用为用户空间程序提供了与硬件和系统资源交互的能力。用户程序通过调用这些系统调用来请求内核执行特权操作,从而实现各种功能。

Linux OS与Linux内核的联系

Linux 系统除了 Linux 内核之外,还包含多个其他组件和工具,这些组件共同构成了一个完整的操作系统。以下是一些主要的组成部分:

  1. 用户空间工具

    • Shell:命令行界面(如 Bash、Zsh),用户通过它与系统交互。
    • 核心工具集:如 GNU Core Utilities(coreutils),提供基本的文件操作、文本处理等命令(如 lscpmvrm 等)。
  2. 系统库

    • C 标准库:如 GNU C Library(glibc),提供系统调用的封装和其他标准库函数,供用户程序使用。
    • 其他库:如 POSIX 兼容库、图形库(如 GTK、Qt)等。
  3. 图形用户界面(GUI)

    • 窗口系统:如 X Window System(X11)或 Wayland,提供图形显示和窗口管理功能。
    • 桌面环境:如 GNOME、KDE、XFCE 等,提供用户友好的图形界面和应用程序。
  4. 设备驱动程序

    • 驱动程序是内核的一部分,负责与硬件设备(如硬盘、网络适配器、显卡等)进行交互,提供设备的功能。
  5. 系统管理工具

    • 包括用于管理用户、进程、网络、文件系统等的工具和命令(如 systemdinitcrontophtop 等)。
  6. 包管理系统

    • 用于安装、更新和管理软件包的工具,如 APT(Debian/Ubuntu)、YUM/DNF(Fedora/RHEL)等。
  7. 应用程序

    • 各种用户应用程序,如文本编辑器(如 Vim、Emacs)、浏览器(如 Firefox、Chrome)、办公软件(如 LibreOffice)等。
  8. 文档和帮助系统

    • 包括手册页(man pages)、在线文档和帮助文件,提供使用系统和应用程序的指导。

总结

Linux 系统是一个完整的操作系统,除了 Linux 内核之外,还包括用户空间工具、系统库、图形用户界面、设备驱动程序、系统管理工具、包管理系统、应用程序以及文档和帮助系统等多个组件。这些组件共同工作,为用户提供一个功能丰富、灵活且可定制的计算环境。

服务与系统调用

服务是基于系统调用的

在Linux系统中,服务通常是指在后台运行的进程,它们提供特定的功能或服务,例如网络服务、数据库服务等。
服务可以被视为特殊的进程,因为它们通常在系统启动时自动启动,并在用户登录之前或之后继续运行。

Ubuntu系统中,服务是一个重要的概念,通常通过systemd来管理。

除了服务,Ubuntu和其他Linux系统中还有一些其他重要的概念和单元:

进程(Process):运行中的程序实例,每个进程都有自己的地址空间、数据和状态。

守护进程(Daemon):一种特殊类型的服务进程,通常在后台运行,负责处理系统或应用程序的任务。

系统守护进程(System Daemon):如systemd、init等,负责启动和管理系统服务。

用户空间和内核空间:用户空间是用户应用程序运行的环境,而内核空间是操作系统内核运行的环境。

包管理(Package Management):Ubuntu使用apt(Advanced Package Tool)来安装、更新和管理软件包。

文件系统(File System):Linux的文件系统结构是分层的,根目录(/)是所有文件和目录的起点。

权限和用户管理:Linux是多用户系统,用户和组的权限管理是其安全性的重要部分。

网络配置:包括网络接口、IP地址、路由等配置,通常通过ifconfig、ip命令或NetworkManager进行管理。

日志管理:系统和服务的日志通常存储在/var/log目录下,systemd的journalctl命令可以查看日志。

这些概念和单元共同构成了Ubuntu及其他Linux系统的基础,理解它们对于有效管理和使用系统非常重要。

Sandbox

  1. Sandbox限制用户程序对系统资源、系统文件的访问,防止其读取或修改敏感文件;
  2. 提供了一个隔离的环境,使得程序之间相互独立。这样可以防止一个程序的错误或崩溃影响到其他程序或系统的稳定性。

让程序运行在sandbox中

Firejail 是一个轻量级的沙箱工具,可以快速将程序运行在沙箱中。它使用 Linux 的命名空间和 seccomp 等特性来限制程序的访问。

使用 Firejail 运行程序的示例:

firejail --net=none --private /path/to/your/program

DBUS

D-Bus(Desktop Bus)是一个消息总线系统,主要用于在 Linux 和其他类 Unix 操作系统中实现进程间通信(IPC)。它允许不同的应用程序和服务之间进行通信和数据交换。D-Bus 的主要作用和特点包括:

特点

1. 进程间通信

D-Bus 提供了一种机制,使得不同的进程能够相互发送消息和调用方法。这对于需要协同工作的应用程序和服务非常重要。

2. 服务发现

D-Bus 允许应用程序在运行时发现其他服务和应用程序。通过 D-Bus,应用程序可以查询系统中可用的服务,并与之进行交互。

3. 异步通信

D-Bus 支持异步消息传递,这意味着发送方可以在不等待接收方响应的情况下继续执行其他操作。这种非阻塞的通信方式提高了系统的响应性和性能。

4. 信号机制

D-Bus 支持信号机制,允许应用程序在特定事件发生时通知其他应用程序。例如,当某个设备连接或断开时,系统可以通过 D-Bus 发送信号,通知相关的应用程序进行相应的处理。

5. 安全性

D-Bus 提供了访问控制机制,允许系统管理员配置哪些用户或应用程序可以访问特定的服务。这有助于保护系统的安全性,防止未授权的访问。

总结

D-Bus 是一个强大的进程间通信机制,广泛应用于 Linux 系统中。它提供了服务发现、异步通信、信号机制和安全性等功能,使得不同的应用程序和服务能够高效地协同工作。通过 D-Bus,开发者可以构建更加灵活和响应迅速的应用程序。

与系统总线的区别

D-Bus 和硬件总线是两个不同层次的概念,分别用于不同的目的和上下文。以下是它们之间的主要区别:

1. 层次和功能

  • D-Bus

    • D-Bus 是一种软件层面的消息总线系统,主要用于进程间通信(IPC)。
    • 它允许不同的应用程序和服务在同一台计算机上进行消息传递和数据交换。
    • D-Bus 主要用于操作系统和应用程序之间的通信,特别是在 Linux 和其他类 Unix 系统中。
  • 硬件总线

    • 硬件总线是计算机硬件层面的物理连接,用于在计算机内部或计算机与外部设备之间传输数据。
    • 硬件总线负责连接 CPU、内存、存储设备、输入输出设备等硬件组件,允许它们相互通信。
    • 常见的硬件总线包括 PCI、USB、SATA、I2C 等。

2. 通信方式

  • D-Bus

    • D-Bus 使用消息传递机制,支持异步通信和信号机制。
    • 它允许应用程序通过发送和接收消息来进行交互,通常是基于高层次的 API。
  • 硬件总线

    • 硬件总线使用电信号或光信号在物理层面上传输数据。
    • 通信通常是基于低级协议,涉及数据包的传输和硬件地址的管理。

3. 应用场景

  • D-Bus

    • D-Bus 主要用于操作系统中的应用程序之间的通信,例如桌面环境中的应用程序、系统服务和用户界面组件之间的交互。
    • 例如,音量控制、设备管理和系统通知等功能通常依赖于 D-Bus。
  • 硬件总线

    • 硬件总线用于连接和通信计算机内部的硬件组件,确保数据在硬件之间的传输。
    • 例如,USB 总线用于连接外部设备(如鼠标、键盘、打印机等)到计算机。

总结

D-Bus 和硬件总线在层次、功能、通信方式和应用场景上有显著区别。D-Bus 是一种软件层面的进程间通信机制,而硬件总线是物理层面的数据传输通道。两者在计算机系统中各自发挥着重要的作用,但它们的工作原理和应用领域是不同的。

实现-基于syscall

是的,D-Bus 是基于系统调用实现的。D-Bus 作为一个进程间通信(IPC)机制,依赖于操作系统提供的底层功能来实现其消息传递和服务发现的能力。以下是 D-Bus 如何利用系统调用的几个方面:

1. Socket 通信

D-Bus 使用 Unix 域套接字(Unix domain sockets)或 TCP/IP 套接字作为其通信机制。套接字是操作系统提供的用于网络和进程间通信的接口,D-Bus 通过系统调用(如 socketbindlistenacceptsendrecv 等)来创建和管理这些套接字。

2. 消息传递

D-Bus 通过套接字发送和接收消息。发送和接收消息的过程涉及到系统调用,这些调用负责将数据从用户空间传输到内核空间,反之亦然。

3. 权限和安全性

D-Bus 还利用系统调用来实现访问控制和权限管理。例如,D-Bus 可以使用 getuidgetgid 等系统调用来检查进程的用户和组权限,以决定是否允许某个进程访问特定的服务或接口。

4. 信号机制

D-Bus 的信号机制允许进程在特定事件发生时通知其他进程。这种机制也依赖于系统调用来处理信号的发送和接收。

总结

因此,D-Bus 是基于系统调用实现的,它利用操作系统提供的底层功能(如套接字和权限管理)来实现进程间的消息传递和服务发现。通过这些系统调用,D-Bus 能够在不同的应用程序和服务之间提供高效的通信机制。


网站公告

今日签到

点亮在社区的每一天
去签到