系统编程(网络,文件基础)

网络链接

虚拟机和主机之间网络连接的主要模式有三种,分别是桥接模式(Bridged)、网络地址转换模式(NAT)以及主机模式(Host-Only)。以下是这三种模式的详细解释:

一、桥接模式(Bridged)

  1. 原理:在桥接模式下,虚拟机的虚拟网络适配器与主机的物理网络适配器进行桥接,使得虚拟机在网络中表现为一个独立的节点,与主机和其他网络设备处于同一网段。
  2. 特点
    • 虚拟机可以访问网络中的其他设备,也可以被其他设备访问。
    • 虚拟机需要手动配置IP地址(或者通过DHCP自动获取),且该IP地址应与主机所在网段相匹配。
    • 由于虚拟机在网络中表现为独立节点,因此可能会占用网络中的DHCP资源,并可能造成IP地址冲突。

二、网络地址转换模式(NAT)

  1. 原理:NAT模式下,虚拟机通过主机的网络适配器访问外部网络(如互联网),但外部网络无法直接访问虚拟机。主机充当虚拟机的网关和NAT路由器,对虚拟机发出的数据包进行地址转换。
  2. 特点
    • 虚拟机可以访问外部网络,但外部网络无法直接访问虚拟机(除非进行端口转发配置)。
    • 虚拟机通常会被分配一个私有IP地址,该地址在虚拟机和主机之间有效,与外部网络隔离。
    • NAT模式有助于保护虚拟机免受外部网络的直接攻击,并减少IP地址冲突的可能性。

三、主机模式(Host-Only)

  1. 原理:在主机模式下,虚拟机与主机通过虚拟网络适配器进行连接,形成一个独立的局域网。该局域网完全隔离于外部网络,因此虚拟机无法访问外部网络,也无法被外部网络访问。
  2. 特点
    • 虚拟机只能与主机进行通信,无法访问外部网络。
    • 该模式适用于需要完全隔离的虚拟环境,如测试和开发环境。
    • 由于虚拟机与外部网络隔离,因此安全性较高,但同时也无法与外部网络进行交互。

虚拟机与主机之间的网络连接模式各有优缺点,用户应根据实际需求选择合适的模式。例如,对于需要与外部网络通信的虚拟机,可以选择桥接模式;对于需要访问外部网络但无需外部设备访问虚拟机的情况,可以选择NAT模式;对于需要完全隔离的虚拟环境,则可以选择主机模式。

文件操作

系统调用

系统调用,由操作系统直接提供,他们是通向操作系统(内核)本身的接口,针对文件操作来说,系统调用是最直接的方式。

文件操作函数参考(文件属性)

函数名 access
头文件 #include <fcntl.h> #include <unistd.h>
函数原型 int access(const char *pathname, int mode)
功能 确定文件或文件夹是否存在,访问权限
参数说明 pathname:要操作的文件名或路径,也可以是目录名; 注意:如果Pathname 为目录名,则mode 只能取值 F_OK,用来判断目录是否存在;2. mode :判断模式,可取值如下: R_OK:判断文件是否有读权限 W_OK :判断文件是否有写权限 X_OK:判断文件是否有执行权限 F_OK:判断文件是否存在
返回值 如果指定的mode 方式有效,返回0,否则返回-1, 错误码放在errno

文件操作函数参考(打开文件)

函数名 open
头文件 #include <fcntl.h> #include <unistd.h>
函数原型 int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode );
功能 打开或创建文件
参数说明 pathname:要操作的文件名或路径;2. flags:文件打开方式,可取值如下: O_RDONLY:只读 O_WRONLY: 只写 O_RDWR: 读写 附加选项:O_APPEND,O_CREAT,O_TRUNC, ...3.mode:如果以新建方式打开文件,这个参数用于设置文件的访问权限,(详见下页)
返回值 如果成功,返回文件描述符,否则返回-1,错误码放在errno
c 复制代码
S_IRWXU  00700 文件拥有者可读,可写,可执行
S_IRUSR   00400 文件拥有者可读
S_IWUSR  00200 文件拥有者可写
S_IXUSR   00100 文件拥有者可执行 

S_IRWXG  00070 组用户可读,可写,可执行
S_IRGRP   00040 组用户可读
S_IWGRP  00020 组用户可写
S_IXGRP   00010 组用户可执行

S_IRWXO  00007 其他组用户可读,可写,可执行
S_IROTH   00004 其他组用户可读
S_IWOTH  00002 其他组用户可写
S_IXOTH   00001 其他组用户可执行

文件操作函数参考(文件读取)

函数名 read
头文件 #include <fcntl.h> #include <unistd.h>
函数原型 ssize_t read(int fd, void *buf, size_t count);
功能 从文件中读取数据
参数说明 fd:要操作的文件描述符;buf:数据缓冲区,用来临时存放读取到的数据:3.count:设置要读取的字节数
返回值 成功:返回实际读取到的字节数0 :到达文件尾部,或没有可读的数据出错:返回 -1,并将错误码存入 errno 中

文件操作函数参考(文件写入)

函数名 write
头文件 #include <fcntl.h> #include <unistd.h>
函数原型 ssize_t write(int fd, const void *buf, size_t count)
功能 写数据到某个文件
参数说明 fd:要操作的文件描述符;buf:数据缓冲区,临时存放要写入的数据:count:要写入的字节数
返回值 成功:返回实际写入到文件的字节数出错:返回 -1,并将错误码存入 errno 中

文件操作函数参考(关闭文件)

函数名 close
头文件 #include <fcntl.h>#include <unistd.h>
函数原型 int close(int fd)
功能 关闭已打开的文件
参数说明 fd:要操作的文件描述符;
返回值 成功,返回0,失败返回-1,并将错误码放入 errno

文件操作函数参考(文件指针移动)

函数名 lseek
头文件 #include <fcntl.h> #include <unistd.h>
函数原型 off_t lseek(int fd, off_t offset, int whence)
功能 移动文件指针
参数说明 fd:要操作的文件描述符;offset:相对于whence 的偏移量:whence:移动方式,可取以下值: SEEK_SET: 文件头部 SEEK_CUR: 当前位置 SEEK_END: 文件末尾
返回值 成功:返回文件指针的偏移量出错:返回 -1,并将错误码存入 errno 中

练习

1.从命令行输入多个文件或目录,要求能一一判断出是否存在;

c 复制代码
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    // 从命令行参数中获取文件或目录路径(跳过第一个参数,即程序名)
    for (int i = 1; i < argc; i++)
    {
        // 使用access函数检查文件或目录是否存在
        if (access(argv[i], F_OK) == 0)
        {
            printf("%s 存在\n", argv[i]);
        }
        else
        {
            printf("%s 不存在\n", argv[i]);
        }
    }
    return 0;
}

2.打开一个全英文的文本文件,对这个文件进行统计,统计有多少行?

c 复制代码
#include <stdio.h> // 包含标准输入输出库,用于打印错误信息和使用printf函数
#include <stdlib.h> // 包含标准库,用于调用exit函数
#include <fcntl.h> // 包含文件控制库,用于open函数
#include <unistd.h> // 包含POSIX操作系统API,用于read和close函数

#define BUFFER_SIZE 1024 // 定义缓冲区大小为1024字节

int main(int argc, char *argv[]) {
    // 检查命令行参数数量,确保用户提供了一个文件名
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]); // 打印使用说明
        exit(EXIT_FAILURE); // 退出程序,返回失败状态
    }

    const char *filename = argv[1]; // 从命令行参数中获取文件名
    int fd = open(filename, O_RDONLY); // 以只读方式打开文件,获取文件描述符
    if (fd == -1) { // 检查文件是否成功打开
        perror("open"); // 如果打开失败,打印错误信息
        exit(EXIT_FAILURE); // 退出程序,返回失败状态
    }

    ssize_t bytesRead; // 定义变量来存储每次read函数调用的返回值
    char buffer[BUFFER_SIZE]; // 定义缓冲区,用于存储从文件中读取的数据
    int lineCount = 0; // 定义变量来计数文件中的行数
    
    // 循环读取文件内容,直到read函数返回0(文件结束)或-1(出错)
    while ((bytesRead = read(fd, buffer, BUFFER_SIZE)) > 0) {
        for (ssize_t i = 0; i < bytesRead; i++) { // 遍历缓冲区中的每个字符
            if (buffer[i] == '\n') { // 如果字符是换行符
                lineCount++; // 行数加1
            }
        }
    }

    if (bytesRead == -1) { // 如果read函数返回-1,表示出错
        perror("read"); // 打印错误信息
        close(fd); // 关闭文件描述符
        exit(EXIT_FAILURE); // 退出程序,返回失败状态
    }

    // 打印文件名和行数
    printf("文件 %s 有 %d 行\n", filename, lineCount);

    // 关闭文件描述符
    close(fd);

    // 程序正常结束,返回成功状态
    return 0;
}

3.打开一篇全英文的文本文件,统计文章中有哪一个英文字母用的最多,用了多少次。

c 复制代码
#include <stdio.h> // 引入标准输入输出库,用于printf和perror等函数
#include <stdlib.h> // 引入标准库,用于exit函数
#include <fcntl.h> // 引入文件控制库,用于open函数
#include <unistd.h> // 引入POSIX操作系统API,用于read和close函数

#define BUFFER_SIZE 1024 // 定义缓冲区大小为1024字节

// 自定义函数,检查字符是否为字母
int is_alpha(char ch)
{
    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); // 判断字符是否在'a'-'z'或'A'-'Z'范围内
}

// 自定义函数,将大写字母转换为小写字母
char to_lower(char ch)
{
    if (ch >= 'A' && ch <= 'Z') // 判断字符是否为大写字母
    {
        return ch + ('a' - 'A'); // 将大写字母转换为小写字母,通过ASCII码计算
    }
    return ch; // 如果不是大写字母,则直接返回原字符
}

int main(int argc, char *argv[]) // 程序的主入口
{
    if (argc != 2) // 判断命令行参数数量是否为2(程序名+文件名)
    {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]); // 如果参数数量不对,则打印用法信息
        exit(EXIT_FAILURE); // 并以失败状态退出程序
    }

    const char *filename = argv[1]; // 获取文件名参数
    int fd = open(filename, O_RDONLY); // 以只读方式打开文件,并获取文件描述符
    if (fd == -1) // 如果文件打开失败
    {
        perror("open"); // 打印错误信息
        exit(EXIT_FAILURE); // 并以失败状态退出程序
    }

    ssize_t bytesRead; // 定义变量用于存储每次read函数调用的返回值
    char buffer[BUFFER_SIZE]; // 定义缓冲区用于存储从文件中读取的数据
    int letterCounts[26] = {0}; // 定义并初始化一个大小为26的数组,用于记录每个英文字母的出现次数
    char mostFrequentLetter = '\0'; // 定义变量用于存储出现次数最多的字母
    int maxCount = 0; // 定义变量用于存储出现次数的最大值

    while ((bytesRead = read(fd, buffer, BUFFER_SIZE)) > 0) // 循环读取文件内容,直到读取不到数据为止
    {
        for (ssize_t i = 0; i < bytesRead; i++) // 遍历缓冲区中的每个字符
        {
            char ch = buffer[i]; // 获取当前字符
            if (is_alpha(ch)) // 如果当前字符是字母
            {                             // 
                ch = to_lower(ch);        // 将字母转换为小写
                letterCounts[ch - 'a']++; // 更新对应字母的计数(通过ASCII码计算索引)

                // 检查是否需要更新出现次数最多的字母
                if (letterCounts[ch - 'a'] > maxCount)
                {
                    maxCount = letterCounts[ch - 'a']; // 更新最大出现次数
                    mostFrequentLetter = ch; // 更新出现次数最多的字母
                }
            }
        }
    }

    if (bytesRead == -1) // 如果read函数调用失败
    {
        perror("read"); // 打印错误信息
        close(fd); // 关闭文件描述符
        exit(EXIT_FAILURE); // 并以失败状态退出程序
    }

    printf("文件"%s"中最常见的字母是"%c",出现次数为 %d\n", filename, mostFrequentLetter, maxCount); // 打印结果信息

    close(fd); // 关闭文件描述符
    return 0; // 程序正常退出
}
相关推荐
Themberfue17 分钟前
HTTP/HTTPS ③-HTTP状态码
网络·网络协议·计算机网络·http
白驹过隙^^30 分钟前
TR-069协议学习--Soap报文、事件、RPC方法
网络·网络协议·学习·rpc
嘤国大力士1 小时前
银河麒麟服务器操作系统桌面任务栏网络图标消失问题
服务器·网络
Pandaconda1 小时前
【新人系列】Python 入门(二十五):Socket 网络编程
开发语言·网络·笔记·后端·python·面试·网络编程
weixin_430750932 小时前
BGP的local_preference本地优先级属性
运维·网络·华为
KeyBordkiller3 小时前
小米路由器IPv6 功能使用指南
运维·网络·智能路由器
大丈夫立于天地间3 小时前
OSPF - 特殊区域
网络·网络协议·学习·算法·信息与通信
xianwu5433 小时前
反向代理模块。
linux·开发语言·网络·c++·git
却染人间愁3 小时前
Android原生开发同一局域网内利用socket通信进行数据传输
linux·服务器·网络