-
计算机网络基础(OSI七层模型、TCP/IP四层模型)
第一部分:网络编程基础
第1章 网络编程核心概念
1.1 计算机网络基础(OSI七层模型、TCP/IP四层模型)
一、为什么要学网络模型?
之前做TCP服务器时,客户端连接后发送数据总是乱序,排查了3天才发现是路由器的分片重组出了问题——如果早懂网络模型,就能立刻定位到是传输层以下的问题,不用在应用层瞎折腾。网络模型是网络编程的“地图”,不懂模型就像开车不认路,全靠瞎vb.net教程C#教程python教程SQL教程access 2010教程撞。这节就带你把OSI七层模型和TCP/IP四层模型掰碎了讲,结合C#代码实战,让你不仅“背下来”,更能“用起来”。
二、OSI七层模型:从物理网线到应用程序
OSI(Open Systems Interconnection)是国际标准化组织制定的网络通信标准,把网络通信分成7层,每层只做一件事,上层依赖下层,下层为上层提供服务。
| 层级 | 名称 | 核心功能 | 常用协议/设备 | 类比生活场景 |
|---|---|---|---|---|
| 7 | 应用层 | 直接为用户提供服务 | HTTP、HTTPS、FTP、SMTP | 快递收件人(用户) |
| 6 | 表示层 | 数据格式转换、加密解密 | SSL/TLS、JPEG、JSON | 快递打包/拆包(格式转换) |
| 5 | 会话层 | 建立、管理、终止会话 | RPC、NetBIOS | 快递取件码(会话标识) |
| 4 | 传输层 | 端到端的可靠传输 | TCP、UDP | 快递员(负责点对点配送) |
| 3 | 网络层 | 路由选择、跨网络传输 | IP、ICMP、OSPF | 快递中转站(路由转发) |
| 2 | 数据链路层 | 物理地址寻址、帧同步 | Ethernet、ARP、PPP | 快递分拣中心(按地址分拣) |
| 1 | 物理层 | 二进制数据的物理传输 | 网线、光纤、WiFi | 快递运输车(物理介质) |
-
物理层:电信号的“搬运工”
核心功能:把二进制数据(0和1)转换成电信号、光信号或无线信号,通过物理介质(网线、光纤、WiFi)传输。
你需要知道:
物理层不关心数据含义,只负责“搬砖”;
常见物理介质:双绞线(网线)、光纤、WiFi(2.4G/5G);
常见标准:以太网(Ethernet)、WiFi 802.11。
C#实战:检测物理网络状态
csharp
using System.Net.NetworkInformation;
// 获取所有网络接口
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var iface in interfaces)
{
// 只显示物理网络接口(排除虚拟网卡)
if (iface.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
iface.OperationalStatus == OperationalStatus.Up)
{
Console.WriteLine($"网卡名称:{iface.Name}");
Console.WriteLine($"物理地址:{iface.GetPhysicalAddress()}"); // 数据链路层MAC地址
Console.WriteLine($"网络类型:{iface.NetworkInterfaceType}");
Console.WriteLine($"状态:{iface.OperationalStatus}");
Console.WriteLine("------------------------");
}
}
代码逐行讲:
1.NetworkInterface.GetAllNetworkInterfaces():获取系统所有网络接口,包括物理网卡、虚拟网卡、Loopback网卡;
2.NetworkInterfaceType.Loopback:排除回环网卡(127.0.0.1),只看物理网络;
3.OperationalStatus.Up:只显示已连接的网络接口;
4.GetPhysicalAddress():获取数据链路层的MAC地址(物理地址),这是物理层和数据链路层的标识。
2. 数据链路层:给数据“贴地址标签”
核心功能:把物理层的二进制数据封装成“帧”,添加源MAC地址和目标MAC地址,实现同一局域网内的通信。
你需要知道:
MAC地址:每个网卡的唯一标识,由12位十六进制数组成(如00-1A-2B-3C-4D-5E);
ARP协议:通过IP地址查找MAC地址(地址解析协议);
PPP协议:拨号上网的链路层协议(如ADSL)。
C#实战:获取MAC地址与IP地址映射
csharp
using System.Net;
using System.Net.NetworkInformation;
// 获取ARP缓存表(IP地址与MAC地址的映射)
var arpEntries = ArpCache.GetArpEntries();
foreach (var entry in arpEntries)
{
Console.WriteLine($"IP地址:{entry.IpAddress}");
Console.WriteLine($"MAC地址:{entry.MacAddress}");
Console.WriteLine($"接口索引:{entry.InterfaceIndex}");
Console.WriteLine("------------------------");
}
// 自定义ARP缓存读取类
public static class ArpCache
{
public static List<ArpEntry> GetArpEntries()
{
var entries = new List<ArpEntry>();
// 调用Windows API读取ARP缓存(需要管理员权限)
var buffer = new byte[1024];
int length = buffer.Length;
if (NativeMethods.GetIpNetTable(buffer, ref length, false) == 0)
{
int offset = 0;
int count = BitConverter.ToInt32(buffer, offset);
offset += 4;
for (int i = 0; i < count; i++)
{
var ipAddress = new IPAddress(BitConverter.ToInt32(buffer, offset));
offset += 4;
var macBytes = new byte[6];
Array.Copy(buffer, offset, macBytes, 0, 6);
offset += 6;
var macAddress = string.Join("-", macBytes.Select(b => b.ToString("X2")));
entries.Add(new ArpEntry { IpAddress = ipAddress, MacAddress = macAddress });
}
}
return entries;
}
}
public class ArpEntry
{
public IPAddress IpAddress { get; set; } = null!;
public string MacAddress { get; set; } = null!;
public int InterfaceIndex { get; set; }
}
// 导入Windows API
internal static class NativeMethods
{
[System.Runtime.InteropServices.DllImport("iphlpapi.dll")]
public static extern int GetIpNetTable(byte[] pIpNetTable, ref int pdwSize, bool bOrder);
}
代码逐行讲:
1.GetIpNetTable:调用Windows系统API读取ARP缓存表,需要管理员权限;
2.ArpEntry:存储IP地址与MAC地址的映射关系;
3.BitConverter.ToInt32:解析API返回的二进制数据,转换成IP地址和MAC地址;
4.为什么要学这个?当你做局域网通信(如UDP广播)时,需要通过MAC地址定位设备,ARP缓存是关键。
3. 网络层:跨网络的“导航员”
核心功能:把数据链路层的“帧”封装成“数据包”,添加源IP地址和目标IP地址,通过路由选择实现跨网络传输。
你需要知道:
IP地址:网络层的逻辑地址,分为IPv4(32位,如192.168.1.1)和IPv6(128位,如2001:0db8:85a3:0000:0000:8a2e:0370:7334);
ICMP协议:网络层控制协议,用于检测网络连通性(如ping命令);
路由选择:通过路由器选择最优路径,把数据包从源IP发送到目标IP。
C#实战:实现简单的ping功能
csharp
using System.Net;
using System.Net.NetworkInformation;
public static bool PingHost(string ipAddress, int timeout = 1000)
{
try
{
using var ping = new Ping();
// 发送ICMP请求包
var reply = ping.Send(ipAddress, timeout);
// 判断是否连通
return reply.Status == IPStatus.Success;
}
catch (PingException ex)
{
Console.WriteLine($"ping失败:{ex.Message}");
return false;
}
}
// 调用示例
bool isReachable = PingHost("www.baidu.com");
Console.WriteLine($"百度是否可达:{isReachable}");
代码逐行讲:
1.Ping类:.NET内置的ICMP客户端,用于发送ping请求;
2.Send方法:发送ICMP请求包,返回PingReply对象;
3.IPStatus.Success:判断目标主机是否可达;
4.底层原理:ping命令基于ICMP协议,网络层协议,不涉及传输层和应用层,所以ping通不代表应用服务能访问(比如对方服务器禁了ICMP,但HTTP服务正常)。
4. 传输层:端到端的“快递员”
核心功能:把网络层的“数据包”封装成“段”(TCP)或“数据报”(UDP),添加源端口和目标端口,实现端到端的可靠传输。
你需要知道:
端口:传输层的标识,范围0-65535,其中0-1023是知名端口(如HTTP用80,HTTPS用443);
TCP协议:面向连接、可靠传输、有序、重传(适合文件传输、网页浏览);
UDP协议:无连接、不可靠、无序、不重传(适合实时通信、视频通话)。
C#实战:获取本地端口占用情况
csharp
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
// 获取所有TCP连接
var tcpConnections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections();
foreach (var connection in tcpConnections)
{
if (connection.LocalEndPoint is IPEndPoint localEp &&
connection.RemoteEndPoint is IPEndPoint remoteEp)
{
Console.WriteLine($"本地地址:{localEp}");
Console.WriteLine($"远程地址:{remoteEp}");
Console.WriteLine($"连接状态:{connection.State}");
Console.WriteLine("------------------------");
}
}
// 获取所有UDP监听端口
var udpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners();
foreach (var listener in udpListeners)
{
Console.WriteLine($"UDP监听端口:{listener}");
}
代码逐行讲:
1.GetActiveTcpConnections:获取当前系统所有活跃的TCP连接;
2.GetActiveUdpListeners:获取当前系统所有监听的UDP端口;
3.IPEndPoint:包含IP地址和端口号,是传输层的核心标识;
4.为什么要学这个?当你启动TCP服务器提示“端口被占用”时,用这段代码就能找到占用端口的进程。
5. 会话层、表示层、应用层:用户能摸到的“服务”
会话层:负责建立、管理和终止会话(比如你登录微信到退出微信的整个过程),常用协议有RPC、NetBIOS;
表示层:负责数据格式转换和加密解密(比如把JSON转换成二进制,把明文加密成密文),常用协议有SSL/TLS、JPEG;
应用层:直接为用户提供服务(比如浏览器、微信、FTP客户端),常用协议有HTTP、HTTPS、FTP、SMTP。
C#实战:用HttpClient发送HTTP请求(应用层)
csharp
using System.Net.Http;
using System.Threading.Tasks;
public static async Task<string> GetHttpResponse(string url)
{
using var client = new HttpClient();
// 发送HTTP GET请求(应用层协议)
var response = await client.GetAsync(url);
// 确保请求成功
response.EnsureSuccessStatusCode();
// 读取响应内容
return await response.Content.ReadAsStringAsync();
}
// 调用示例
string html = await GetHttpResponse("https://www.baidu.com");
Console.WriteLine(html.Substring(0, 1000)); // 输出前1000个字符
代码逐行讲:
1.HttpClient:.NET内置的HTTP客户端,封装了应用层的HTTP协议;
2.GetAsync:发送HTTP GET请求,底层会自动处理传输层的TCP连接、网络层的IP路由、数据链路层的MAC寻址;
3.EnsureSuccessStatusCode:如果HTTP状态码不是200-299,抛出异常;
4.为什么要学这个?应用层是网络编程的“最终战场”,你写的大部分代码都在应用层,但不懂下层原理,遇到问题就只能“重启试试”。
三、TCP/IP四层模型:工业界的“事实标准”
OSI七层模型是“理论标准”,而TCP/IP四层模型是工业界的“事实标准”,把OSI七层模型合并成四层,更简洁、更实用。
| TCP/IP四层模型 | 对应OSI七层模型 | 核心协议 |
|---|---|---|
| 应用层 | 应用层+表示层+会话层 | HTTP、HTTPS、FTP、SMTP |
| 传输层 | 传输层 | TCP、UDP |
| 网际层 | 网络层 | IP、ICMP |
| 网络接口层 | 数据链路层+物理层 | Ethernet、ARP、PPP |
你需要知道:
TCP/IP是一个协议族,包含IP、TCP、UDP、HTTP等上百个协议;
我们常说的“TCP/IP协议”其实是指TCP/IP协议族;
几乎所有互联网通信都基于TCP/IP四层模型。
四、数据在网络模型中的“旅行”
以你用浏览器访问www.baidu.com为例,数据的传输过程是这样的:
1.应用层:浏览器生成HTTP请求(包含请求头、请求体);
2.传输层:把HTTP请求封装成TCP段,添加源端口(如12345)和目标端口(80);
3.网络层:把TCP段封装成IP数据包,添加源IP(如192.168.1.100)和目标IP(如110.242.68.3);
4.网络接口层:把IP数据包封装成以太网帧,添加源MAC(如00-1A-2B-3C-4D-5E)和目标MAC(如11-22-33-44-55-66);
5.物理层:把以太网帧转换成电信号,通过网线传输到路由器;
6.路由器转发:路由器根据目标IP选择最优路径,把数据包转发到百度服务器;
7.服务器接收:百度服务器从物理层到应用层逐层解封装,最终得到HTTP请求,处理后返回HTTP响应;
8.客户端接收:浏览器从物理层到应用层逐层解封装,得到HTTP响应,渲染成网页。
五、基础知识拓展
-
为什么TCP是可靠的,UDP是不可靠的?
TCP有三次握手(建立连接)、四次挥手(断开连接)、滑动窗口(流量控制)、拥塞控制(避免网络拥堵)、重传机制(丢失的数据包重新发送);
UDP没有这些机制,发送数据后不管对方有没有收到,也不管数据有没有乱序,适合实时性要求高的场景(如视频通话、游戏)。 -
IP地址和MAC地址的区别?
IP地址是逻辑地址,可以手动修改,用于跨网络传输;
MAC地址是物理地址,出厂时固化在网卡上,不能修改,用于同一局域网内的通信;
类比:IP地址是“家庭地址”,MAC地址是“身份证号”,快递员(传输层)用家庭地址找你,分拣中心(数据链路层)用身份证号确认你的身份。 -
端口的作用是什么?
一台电脑可以同时运行多个网络程序(如浏览器、微信、QQ),端口就是用来区分这些程序的;
类比:IP地址是“小区地址”,端口是“门牌号”,快递员(传输层)根据门牌号把快递送到对应的住户(程序)。 -
为什么需要分层?
解耦:每层只做一件事,修改一层不影响其他层(比如把网线换成光纤,只需要修改物理层,应用层完全不用变);
标准化:不同厂商的设备只要遵守同一层的标准,就能互相通信(比如华为的路由器和思科的路由器,只要都遵守IP协议,就能互相转发数据包);
易调试:出问题时可以逐层排查(比如ping不通,先查物理层有没有插网线,再查数据链路层有没有获取到MAC地址,再查网络层有没有获取到IP地址)。
六、总结:网络模型不是“背题”,是“解题工具”
OSI七层模型是“理论教科书”,帮你理解网络通信的完整流程;
TCP/IP四层模型是“实战手册”,帮你快速定位问题和编写代码;
分层的核心是“各司其职”,上层依赖下层,下层为上层提供服务;
学习网络模型的目的不是“背下来每层的名称”,而是“遇到问题时能快速定位到哪一层出了问题”。
比如你用C#写的TCP客户端连不上服务器,按照网络模型排查:
1.物理层:插网线了吗?WiFi连了吗?
2.数据链路层:能ping通服务器吗?ARP缓存有服务器的MAC地址吗?
3.网络层:服务器的IP地址对吗?有没有防火墙禁了IP?
4.传输层:服务器的端口对吗?有没有被占用?防火墙禁了端口吗?
5.应用层:服务器的应用程序启动了吗?协议格式对吗?
按照这个流程排查,90%的问题都能在10分钟内解决——这就是网络模型的价值。下一节我们就用C#实战TCP和UDP编程,把传输层的理论落地成代码。
本站原创,转载请注明出处:










