走近Linux:学习系统编程的基础知识

系统编程的概念

系统编程是指编写操作系统、设备驱动程序和底层系统工具的过程。在系统编程中,我们需要了解计算机硬件和操作系统的内部工作原理,并使用低级语言(如汇编语言和C语言)编写代码来与硬件和操作系统交互。

在Linux系统中,系统编程非常重要,因为Linux是一种开放源代码的操作系统,允许用户修改和调整系统的行为,从而实现定制化的功能。

当进行系统编程时,我们需要了解计算机硬件和操作系统的内部工作原理,以及如何与它们交互。以下是一些系统编程中常用的概念和技术:

1、系统调用:系统调用是用户空间程序与内核空间之间进行通信的接口。它允许用户程序向操作系统请求服务,例如打开文件、读取文件、创建进程等。系统调用通常使用汇编语言或C语言编写,并通过中断或软件陷阱的方式将控制权转移到内核空间。

以下是一个使用系统调用进行文件读写的示例程序:

#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd;
    char buffer[1024];

    fd = open("example.txt", O_RDONLY);
    read(fd, buffer, sizeof(buffer));
    close(fd);

    return 0;
}

在这个示例程序中,我们使用了open()函数打开example.txt文件,并将返回的文件描述符存储在fd变量中。然后,我们使用read()函数从文件中读取数据,并将它们存储在buffer数组中。最后,我们使用close()函数关闭文件。

2、进程管理:进程是正在运行的程序的实例。在Linux中,进程是由内核管理的。通过创建、启动、停止和调度进程,我们可以控制程序的执行和资源使用。在Linux中,我们可以使用fork()函数创建新进程,使用exec()函数启动新程序,使用wait()函数等待子进程结束等。

以下是一个创建子进程的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    pid_t pid;

    pid = fork();

    if (pid < 0) {
        printf("Error: fork failed.\n");
        exit(1);
    } else if (pid == 0) {
        printf("I'm the child process.\n");
        exit(0);
    } else {
        printf("I'm the parent process.\n");
        wait(NULL);
    }

    return 0;
}

在这个示例程序中,我们使用fork()函数创建一个新进程,并将返回的进程ID存储在pid变量中。如果fork()函数返回值小于0,则表示创建进程失败。如果返回值等于0,则表示当前进程是子进程。如果返回值大于0,则表示当前进程是父进程。在父进程中,我们使用wait()函数等待子进程结束,以避免子进程成为僵尸进程。

3、线程管理:线程是进程内的执行单元。在Linux中,线程与进程一样由内核管理。通过创建、启动、停止和调度线程,我们可以实现并发执行和资源共享。在Linux中,我们可以使用pthread库来创建和管理线程。

以下是一个创建线程的示例程序:

#include <stdio.h>
#include <pthread.h>

void *thread_func(void *arg) {
    printf("Hello from thread!\n");
    pthread_exit(NULL);
}

int main() {
    pthread_t thread;

    pthread_create(&thread, NULL, thread_func, NULL);
    pthread_join(thread, NULL);

    printf("Hello from main!\n");

    return 0;
}

在这个示例程序中,我们使用pthread_create()函数创建一个新线程,并将线程ID存储在thread变量中。我们使用NULL作为线程属性,表示使用默认值。我们还将thread_func函数作为新线程的入口点,并将NULL作为参数传递给线程函数。

在主线程中,我们使用pthread_join()函数等待新线程结束。这将阻塞主线程,直到新线程执行完毕。最后,我们在主线程中输出一条消息。

4、内存管理:内存管理是操作系统中非常重要的一个方面。在Linux中,我们可以使用malloc()函数分配内存,使用free()函数释放内存。我们还可以使用mmap()函数将文件映射到内存中,以便快速访问文件内容。

以下是一个使用malloc()函数分配内存的示例程序:

#include <stdlib.h>
#include <stdio.h>

int main() {
    int *ptr;

    ptr = malloc(sizeof(int));
    if (ptr == NULL) {
        printf("Error: malloc failed.\n");
        exit(1);
    }

    *ptr = 42;

    printf("The value is: %d\n", *ptr);

    free(ptr);

    return 0;
}

在这个示例程序中,我们使用malloc()函数分配一个整数大小的内存块,并将返回的指针存储在ptr变量中。如果malloc()函数返回NULL,则表示分配内存失败。然后,我们将整数42存储在分配的内存块中,并在最后释放这个内存块,以避免内存泄漏。

5、文件操作:Linux系统是基于文件的,因此文件操作是系统编程中非常重要的一部分。在Linux中,我们可以使用标准的文件I/O函数(如fopen()、fclose()、fread()和fwrite())来打开、读取和写入文件。此外,Linux还提供了一些特殊的文件I/O函数,如read()和write(),它们可以直接读写文件描述符,而不是文件指针。

以下是一个使用fopen()和fwrite()函数写入文件的示例程序:

#include <stdio.h>

int main() {
    FILE *fp;
    char data[] = "Hello, world!";

    fp = fopen("output.txt", "w");
    if (fp == NULL) {
        printf("Error: cannot open file.\n");
        return 1;
    }

    fwrite(data, sizeof(char), sizeof(data), fp);

    fclose(fp);

    return 0;
}

在这个示例程序中,我们使用fopen()函数打开一个名为output.txt的文件,并将返回的文件指针存储在fp变量中。如果fopen()函数返回NULL,则表示打开文件失败。然后,我们使用fwrite()函数将字符串"Hello, world!"写入文件中,并在最后关闭文件。

6、网络编程:网络编程是系统编程中另一个重要的方面。在Linux中,我们可以使用套接字(socket)来创建网络连接,使用标准的套接字函数(如bind()、listen()、accept()、connect()、send()和recv())来发送和接收数据。

以下是一个使用socket和bind函数创建简单的TCP服务器的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define PORT 8888

int main(int argc, char const *argv[]) {
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char *hello = "Hello from server";

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the port 8888
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
                                                  &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 );

    // Forcefully attaching socket to the port 8888
    if (bind(server_fd, (struct sockaddr *)&address,
                                 sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

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

    valread = read( new_socket , buffer, 1024);
    printf("%s\n",buffer );
   

在前面的示例程序中,我们使用socket()函数创建了一个TCP套接字。然后,我们使用bind()函数将套接字绑定到本地地址(IP地址为INADDR_ANY,端口号为8888)。接下来,我们使用listen()函数将套接字设置为监听状态,并在循环中使用accept()函数接受客户端连接。一旦有客户端连接成功,我们就使用read()函数从客户端接收数据,并使用printf()函数在服务器端将接收到的数据打印出来。

这只是一个简单的示例程序,实际的网络编程中还需要考虑更多的细节和安全性问题。

总结:

系统编程是编写底层操作系统代码的过程,包括处理进程、线程、内存、文件系统和网络等方面。在Linux系统中,系统编程通常使用C语言,并且可以使用系统调用和库函数来访问底层操作系统功能。在本文中,我们讨论了系统编程的一些基本概念,并给出了一些示例代码来说明这些概念的应用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值