📱 虚拟机网络修复
当虚拟机突然没有网络标志时,可以使用以下命令快速修复:
bash
nmcli network off
nmcli network on
这两个命令会重启网络管理器服务,通常可以解决临时的网络连接问题。
🌐 网络基础理论
1. 认识网络(了解)
网络:指多台设备之间进行通信和资源共享的系统。现代网络技术使得不同地理位置的计算机能够相互连接和交换数据。
Internet发展史:从ARPANET到现代互联网的演进过程。
2. IP地址详解
2.1 基本概念
- IP地址:Internet中主机的唯一标识符
- 通信前提:Internet中的主机要与别的机器通信必须有一个IP地址
- 地址长度:IPv4为32位,IPv6为128位
- 表示形式:常用点分十进制形式,如192.168.1.217,最终都会转换为32位无符号整数
- 地址分类:A、B、C、D、E五类
2.2 IP地址二级划分
二级划分公式:IP地址 = 网络号 + 主机号
- 网络号:标识设备所在的网络段(局域网)
- 主机号:标识在本网段内的具体设备ID,同一局域网内不能重复


IP地址取值范围
| 类别 | 地址范围 | 用途说明 |
|---|---|---|
| A类 | 1.0.0.0 ~ 126.255.255.255 | 大型网络,政府机构等 |
| B类 | 128.0.0.0 ~ 191.255.255.255 | 中型网络,大学、大型企业 |
| C类 | 192.0.0.0 ~ 223.255.255.255 | 小型网络,小型企业、家庭 |
| D类 | 224.0.0.0 ~ 239.255.255.255 | 组播地址(Multicast) |
| E类 | 240.0.0.0 ~ 255.255.255.255 | 保留地址,实验和研究使用 |
2.3 特殊地址
以下地址不会分配给主机使用:
1. 网络地址
用于标识网络的地址,有效网络号,主机号全为0。
示例转换:
- 192.168.30.182 → 192.168.30.0
- 128.1.2.3 → 128.1.0.0
- 12.1.2.5 → 12.0.0.0
2. 广播地址
用于给局域网内所有主机发送数据,有效的网络号,主机号全为1。
示例转换:
- 192.168.30.182 → 192.168.30.255
- 128.1.2.3 → 128.1.255.255
- 12.1.2.5 → 12.255.255.255
3. 其他特殊地址
- 0.0.0.0:在服务器中表示监听本机上所有的IPv4地址,接受来自任意源IP地址的数据包,常用于服务器程序监听所有网络接口的连接请求。
- 127.0.0.1:回环地址/本机地址,一般用于测试。所有发往该类地址的数据包都应该被loop back原样送回,即当在计算机上访问127.0.0.1时,实际上是在与自己进行网络通信。
练习
问题:C类地址,同一网段最多可以连接多少个主机?
答案:254个(排除网络地址和广播地址)
2.4 子网掩码
作用:将IP地址划分为网络地址和主机地址两部分。
特点
- 子网掩码长度和IP地址长度完全一样,由32位二进制组成
- 网络号全为1,主机号全为0
默认子网掩码
- A类:255.0.0.0
- B类:255.255.0.0
- C类:255.255.255.0
练习
问题:子网掩码255.255.255.0,该网段可以容纳多少台主机?
答案:254台
计算公式
- IP地址 & 子网掩码 = 网络地址
- IP地址 & ~子网掩码 = 主机号
2.5 三级划分
- 二级划分 = 网络号 + 主机号
- 三级划分 = 网络号 + 子网号 + 主机号
三级划分的子网掩码:网络号和子网号都是1,主机号是0。
子网划分练习
场景:某公司有四个部门:行政、研发1、研发2、营销,每个部门各40台计算机接入公司局域网交换机。如果要在192.168.1.0网段为每个部门划分子网,子网掩码应该怎么设置?每个子网的地址范围分别是什么?(4个部门之间不能通信)
分析:
- 192.168.1.0属于C类地址
- 默认子网掩码:255.255.255.0
- 划分4个网段需要将2位二进制从主机号划分成子网号(2²=4)
- 高两位分别可以是:00、01、10、11
- 三级划分后的子网掩码:255.255.255.192(二进制:11111111.11111111.11111111.11000000)
各部门地址范围:
| 部门 | 二进制范围 | 十进制范围(去除网络地址和广播地址) |
|---|---|---|
| 部门1(行政) | 192.168.1.00 000000 ~ 192.168.1.00 111111 | 192.168.1.1 ~ 192.168.1.62 |
| 部门2(研发1) | 192.168.1.01 000000 ~ 192.168.1.01 111111 | 192.168.1.65 ~ 192.168.1.126 |
| 部门3(研发2) | 192.168.1.10 000000 ~ 192.168.1.10 111111 | 192.168.1.129 ~ 192.168.1.190 |
| 部门4(营销) | 192.168.1.11 000000 ~ 192.168.1.11 111111 | 192.168.1.193 ~ 192.168.1.254 |
补充:DNS(域名系统)
由于使用IP地址来指定计算机不方便人们记忆,且输入时容易出错,因此使用字符表示网络中计算机名称的方法应运而生。这种命名方法就像每个人的名字,这就是域名(Domain Name)。
DNS相关概念
- 域名服务器(Domain Name Server):用来处理IP地址和域名之间的转换
- 域名系统(Domain Name System,DNS):将域名翻译成IP地址的软件系统
- 特性:一个域名可以绑定多个IP地址
- 公共DNS:可以在网络中配置自己的DNS服务器,如114.114.114.114、8.8.8.8

域名结构
以域名www.baidu.com.cn为例,从右向左看:
- cn:高级域名,也叫一级域名,通常分配给主干节点,取名为国家名,cn代表中国
- com :网络名,属于二级域名,通常表示组织或部门。中国互联网二级域名共40个:
- edu:教育部门
- com:商业部门
- gov:政府部门
- mil:军队
- 等等
- baidu:机构名,属于三级域名,表示百度公司
- www:万维网(World Wide Web),也叫环球信息网,是一种特殊的信息结构框架
🌍 网络模型
3.1 网络体系结构
网络采用分而治之的方法设计,将网络的功能划分为不同板块,以分层的形式有机组合在一起。
- 每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的
- 每层向上层提供服务,同时使用下层提供的服务
- 网络体系结构即指网络的层次结构和每层所使用协议的集合
两类非常重要的体系结构:OSI模型与TCP/IP模型
3.2 OSI七层模型
OSI模型是最理想的参考模型,分为七层:
- 物理层:传输的是bit流(0与1的数据),物理信号,没有格式
- 数据链路层:格式变为帧(把数据分成包,一帧一帧的数据进行发送)
- 网络层:路由器中有算法,IP协议(主机到主机),路由转发
- 传输层:端口号,数据传输到具体哪个进程程序(端到端)
- 会话层:通信管理,负责建立或断开通信链接
- 表示层:确保一个系统应用层发送消息可以被另一个系统的应用层读取,编码转换,数据解析,管理数据加密、解密
- 应用层:指定特定应用协议,文件传输,文件管理,电子邮件等
记忆口诀:物→链(联)→网→输(叔)→会→示(使)→用

3.3 TCP/IP四层模型

各层功能
- 网络接口层和物理层:屏蔽硬件差异(驱动),向上提供统一的操作接口
- 网络层:提供端对端的传输,可以理解为通过IP寻址机器
- 传输层:决定数据交给机器的哪个任务(进程)去处理,通过端口寻址
- 应用层:应用协议和应用程序的集合
3.4 常见网络协议
| 层次 | 协议 | 说明 |
|---|---|---|
| 网络接口和物理层 | PPP | 拨号协议(老式电话线上网方式) |
| 网络接口和物理层 | ARP | 地址解析协议,IP→MAC地址转换 |
| 网络接口和物理层 | RARP | 反向地址转换协议,MAC→IP地址转换 |
| 网络层 | IP(IPv4/IPv6) | 网络互联协议,负责数据包的路由和转发 |
| 网络层 | ICMP | Internet控制消息协议,用于网络诊断和错误报告 |
| 网络层 | IGMP | Internet组管理协议,用于组播通信 |
| 传输层 | TCP | 传输控制协议,面向连接、可靠的字节流服务 |
| 传输层 | UDP | 用户数据报协议,无连接、不可靠的数据报服务 |
| 传输层 | SCTP | 流控制传输协议,结合TCP和UDP的优点 |
| 应用层 | HTTP/HTTPS | 超文本传输协议/安全超文本传输协议 |
| 应用层 | FTP | 文件传输协议 |
| 应用层 | SMTP/POP3/IMAP | 电子邮件相关协议 |
| 应用层 | DNS | 域名系统,域名与IP地址转换 |
| 应用层 | DHCP | 动态主机配置协议,自动分配IP地址 |
🔌 SOCKET编程
4.1 Socket基本概念
**Socket(套接字)**是网络通信的端点,是应用层与传输层之间的接口。它提供了进程间通信的机制,允许不同主机上的进程通过网络进行数据交换。
Socket通信模型
- 面向连接的Socket:基于TCP协议,提供可靠的数据传输
- 无连接的Socket:基于UDP协议,提供快速但不保证可靠的数据传输
4.2 Socket通信流程
TCP Socket通信流程
- 服务器端 :
- 创建Socket
- 绑定IP地址和端口
- 监听连接请求
- 接受客户端连接
- 收发数据
- 关闭连接
- 客户端 :
- 创建Socket
- 连接服务器
- 收发数据
- 关闭连接
UDP Socket通信流程
- 服务器端 :
- 创建Socket
- 绑定IP地址和端口
- 接收数据
- 发送数据
- 关闭Socket
- 客户端 :
- 创建Socket
- 发送数据
- 接收数据
- 关闭Socket
4.3 Socket编程示例(C语言)
TCP服务器端示例
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFFER_SIZE 1024
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// 1. 创建Socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 2. 绑定地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("绑定失败");
close(server_fd);
exit(EXIT_FAILURE);
}
// 3. 监听连接
if (listen(server_fd, 5) < 0) {
perror("监听失败");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("服务器启动,等待客户端连接...\n");
// 4. 接受客户端连接
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
perror("接受连接失败");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("客户端连接成功:%s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 5. 接收数据
memset(buffer, 0, BUFFER_SIZE);
int bytes_received = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received < 0) {
perror("接收数据失败");
} else {
printf("收到客户端消息:%s\n", buffer);
// 6. 发送响应
char response[BUFFER_SIZE];
snprintf(response, BUFFER_SIZE, "服务器已收到:%s", buffer);
send(client_fd, response, strlen(response), 0);
}
// 7. 关闭连接
close(client_fd);
close(server_fd);
return 0;
}
TCP客户端示例
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
// 1. 创建Socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
// 3. 连接服务器
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("连接服务器失败");
close(sockfd);
exit(EXIT_FAILURE);
}
// 4. 发送数据
char *message = "Hello Server!";
send(sockfd, message, strlen(message), 0);
// 5. 接收响应
memset(buffer, 0, BUFFER_SIZE);
int bytes_received = recv(sockfd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received < 0) {
perror("接收响应失败");
} else {
printf("服务器响应:%s\n", buffer);
}
// 6. 关闭Socket
close(sockfd);
return 0;
}
UDP服务器端示例
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// 1. 创建UDP Socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 2. 绑定地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("绑定失败");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("UDP服务器启动...\n");
// 3. 接收数据
memset(buffer, 0, BUFFER_SIZE);
int bytes_received = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0,
(struct sockaddr*)&client_addr, &client_len);
if (bytes_received < 0) {
perror("接收数据失败");
} else {
printf("收到客户端消息:%s\n", buffer);
// 4. 发送响应
char response[BUFFER_SIZE];
snprintf(response, BUFFER_SIZE, "服务器已收到:%s", buffer);
sendto(sockfd, response, strlen(response), 0,
(struct sockaddr*)&client_addr, client_len);
}
// 5. 关闭Socket
close(sockfd);
return 0;
}
UDP客户端示例
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
// 1. 创建UDP Socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket创建失败");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
// 3. 发送数据
char *message = "Hello UDP Server!";
sendto(sockfd, message, strlen(message), 0,
(struct sockaddr*)&server_addr, sizeof(server_addr));
// 4. 接收响应
memset(buffer, 0, BUFFER_SIZE);
socklen_t server_len = sizeof(server_addr);
int bytes_received = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0,
(struct sockaddr*)&server_addr, &server_len);
if (bytes_received < 0) {
perror("接收响应失败");
} else {
printf("服务器响应:%s\n", buffer);
}
// 5. 关闭Socket
close(sockfd);
return 0;
}
4.4 Socket编程注意事项
- 端口选择:避免使用0-1023的知名端口,建议使用1024-65535的端口
- 异常处理:网络通信中可能发生各种异常,需要妥善处理
- 资源释放:确保Socket、流等资源在使用后正确关闭
- 并发处理:服务器端通常需要支持多客户端并发连接
- 缓冲区大小:合理设置缓冲区大小,避免内存浪费或数据丢失
4.5 网络编程最佳实践
- 使用线程池:处理并发连接时使用线程池,避免频繁创建销毁线程
- 设置超时:为Socket操作设置合理的超时时间,避免无限等待
- 数据校验:重要数据应添加校验机制,确保数据完整性
- 日志记录:记录关键操作和异常信息,便于问题排查
- 安全考虑:对用户输入进行验证,防止注入攻击