网络链接
虚拟机和主机之间网络连接的主要模式有三种,分别是桥接模式(Bridged)、网络地址转换模式(NAT)以及主机模式(Host-Only)。以下是这三种模式的详细解释:
一、桥接模式(Bridged)
- 原理:在桥接模式下,虚拟机的虚拟网络适配器与主机的物理网络适配器进行桥接,使得虚拟机在网络中表现为一个独立的节点,与主机和其他网络设备处于同一网段。
- 特点 :
- 虚拟机可以访问网络中的其他设备,也可以被其他设备访问。
- 虚拟机需要手动配置IP地址(或者通过DHCP自动获取),且该IP地址应与主机所在网段相匹配。
- 由于虚拟机在网络中表现为独立节点,因此可能会占用网络中的DHCP资源,并可能造成IP地址冲突。
二、网络地址转换模式(NAT)
- 原理:NAT模式下,虚拟机通过主机的网络适配器访问外部网络(如互联网),但外部网络无法直接访问虚拟机。主机充当虚拟机的网关和NAT路由器,对虚拟机发出的数据包进行地址转换。
- 特点 :
- 虚拟机可以访问外部网络,但外部网络无法直接访问虚拟机(除非进行端口转发配置)。
- 虚拟机通常会被分配一个私有IP地址,该地址在虚拟机和主机之间有效,与外部网络隔离。
- NAT模式有助于保护虚拟机免受外部网络的直接攻击,并减少IP地址冲突的可能性。
三、主机模式(Host-Only)
- 原理:在主机模式下,虚拟机与主机通过虚拟网络适配器进行连接,形成一个独立的局域网。该局域网完全隔离于外部网络,因此虚拟机无法访问外部网络,也无法被外部网络访问。
- 特点 :
- 虚拟机只能与主机进行通信,无法访问外部网络。
- 该模式适用于需要完全隔离的虚拟环境,如测试和开发环境。
- 由于虚拟机与外部网络隔离,因此安全性较高,但同时也无法与外部网络进行交互。
虚拟机与主机之间的网络连接模式各有优缺点,用户应根据实际需求选择合适的模式。例如,对于需要与外部网络通信的虚拟机,可以选择桥接模式;对于需要访问外部网络但无需外部设备访问虚拟机的情况,可以选择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; // 程序正常退出
}