从 0 到 1 理解计算机网络:从网络基础到 Socket 编程

🎬 个人主页 :道尔柯南
❄专栏传送门 :《C语言》《C++》《Linux操作系统》

昙花一现,却等待了整个白昼;蝉鸣一夏,却蛰伏了好几个四季。 摘要:

计算机网络看似复杂,但如果从"通信"这个最基本的问题出发,就会发现网络中的许多概念其实都围绕着一件事情展开:如何让不同主机上的不同进程可靠、准确地交换数据。

本文从计算机网络的发展背景出发,逐步理解网络协议、协议分层、OSI 与 TCP/IP 模型,并进一步深入 MAC 地址、IP 地址、端口号、TCP/UDP、网络字节序以及 Socket 编程接口,最终建立一套完整的计算机网络知识框架。


一、计算机网络为什么会出现?

最初的计算机是一台一台独立工作的。

可以简单理解成:

text 复制代码
计算机 A        计算机 B        计算机 C
   ↓               ↓               ↓
各自独立工作,彼此之间没有直接的数据交换

随着计算机数量越来越多,人们很快发现:

一台计算机解决不了所有问题。

计算机本质上是人的工具,而人需要协同工作,因此计算机之间进行数据共享和资源共享就成为必然需求。

于是,计算机从最初的独立模式 逐渐发展到了网络互联。

课件将这一过程概括为:

  • 独立模式:计算机之间相互独立;
  • 网络互联:多台计算机连接起来,实现数据共享;
  • 局域网 LAN:通过交换机、路由器等设备连接更多计算机;
  • 广域网 WAN:进一步把相距很远的计算机连接起来。

所以,从本质上看:

计算机网络,就是为了让不同计算机之间能够进行通信和资源共享。


二、网络通信首先要解决的问题:大家必须"说同一种语言"

两台计算机连接起来之后,是不是就可以直接通信了?

答案是:不一定。

假设:

text 复制代码
计算机 A:我用"频率"表示 0 和 1

计算机 B:我用"电压强弱"表示 0 和 1

即使两台计算机都在传输数据,它们也无法正确理解对方。

这就像两个人:

text 复制代码
A:你好,我说中文。

B:Hello,我说英语。

两个人都在说话,但由于缺少共同约定,仍然无法正常交流。

所以,计算机之间通信需要一套共同遵守的规则。

这就是:

协议(Protocol)

课件对协议给出了一个非常朴素的理解:

"协议"是一种约定。

进一步来看,协议不仅仅是"约定语言",还需要规定:

  • 数据应该是什么格式;
  • 数据如何开始;
  • 数据如何结束;
  • 数据应该如何解释;
  • 出错之后怎么办;
  • 下一步应该交给谁处理。

由于计算机厂商、操作系统、网络设备非常多,因此必须存在一套大家共同遵守的标准,才能让不同设备之间顺畅通信。


三、协议为什么要分层?

如果把整个网络通信过程设计成一个巨大的协议,会出现一个非常严重的问题:

太复杂了。

例如,一次网络通信可能同时涉及:

text 复制代码
应用程序
   ↓
数据格式
   ↓
可靠传输
   ↓
IP寻址
   ↓
局域网通信
   ↓
网卡
   ↓
网线 / Wi-Fi

如果所有功能全部揉在一起,那么任何一个地方发生变化,都可能影响整个系统。

因此,协议也采用了软件工程中非常经典的思想:

模块化 + 解耦合

课件指出,协议本质上也是软件,因此为了更好地进行模块化和解耦,也被设计成层状结构。

可以把它理解成:

text 复制代码
┌──────────────┐
│   应用层     │
├──────────────┤
│   传输层     │
├──────────────┤
│   网络层     │
├──────────────┤
│ 数据链路层   │
├──────────────┤
│   物理层     │
└──────────────┘

每一层只负责自己的事情,并为上一层提供服务。

这就是协议分层。


四、OSI 七层模型:理解网络的经典框架

网络协议分层最经典的模型之一就是:

OSI 七层模型

OSI,即:

Open System Interconnection,开放系统互连。

它从逻辑上把网络通信划分成七层,是一种理论上的参考模型。

通常可以表示为:

text 复制代码
7  应用层
6  表示层
5  会话层
4  传输层
3  网络层
2  数据链路层
1  物理层

OSI 模型的优点非常明显:

  • 概念清晰;
  • 层次明确;
  • 服务、接口和协议进行了区分;
  • 有利于理解不同系统之间如何通信。

但问题也很明显:

模型比较复杂,在实际工程中并没有完全按照七层实现。

因此,实际学习和网络编程中,我们更多使用 TCP/IP 模型。课件也明确指出,OSI 七层模型虽然理论完整,但复杂且不够实用,因此后续按照 TCP/IP 模型进行讲解。


五、TCP/IP 五层模型

TCP/IP 是一组协议的统称,它实际上包含大量不同协议,共同组成 TCP/IP 协议簇。

课件采用的五层模型为:

text 复制代码
┌────────────────────┐
│      应用层        │
├────────────────────┤
│      传输层        │
├────────────────────┤
│      网络层        │
├────────────────────┤
│    数据链路层      │
├────────────────────┤
│      物理层        │
└────────────────────┘

下面逐层理解。


1. 物理层

物理层解决的是最底层的问题:

数据到底通过什么信号传输?

例如:

  • 双绞线;
  • 同轴电缆;
  • 光纤;
  • Wi-Fi 电磁波。

物理层决定了很多底层通信能力,例如:

  • 最大传输速率;
  • 传输距离;
  • 抗干扰能力。

课件中还提到:

Hub(集线器)工作在物理层。


2. 数据链路层

数据链路层主要负责:

相邻设备之间的数据传输。

它涉及:

  • 数据帧;
  • 网卡;
  • 帧同步;
  • 冲突检测;
  • 数据差错校验;
  • MAC 地址。

典型的设备是:

交换机 Switch

课件明确指出,交换机主要工作在数据链路层。


3. 网络层

网络层解决的是:

数据应该往哪里走?

这里最重要的概念就是:

IP 地址

IP 地址用来标识网络中的主机,同时网络层还需要进行路由选择。

例如:

text 复制代码
主机 A
  ↓
路由器 1
  ↓
路由器 2
  ↓
主机 B

这个过程中,数据需要经过一个或多个路由器。

典型的网络层设备就是:

路由器 Router


4. 传输层

传输层负责:

两台主机之间的数据传输。

这里最重要的两个协议就是:

text 复制代码
TCP
UDP

TCP 的特点:

  • 面向连接;
  • 可靠传输;
  • 面向字节流。

UDP 的特点:

  • 无连接;
  • 不可靠传输;
  • 面向数据报。

5. 应用层

应用层离用户最近。

例如:

text 复制代码
浏览网页
发送邮件
文件传输
远程登录

对应的应用层协议可以包括:

  • HTTP;
  • SMTP;
  • FTP;
  • Telnet。

课件指出:

网络编程主要就是针对应用层。


六、真正理解网络:数据到底是怎么发送出去的?

到这里,我们知道了很多概念:

text 复制代码
应用层
传输层
网络层
数据链路层
物理层

但是一个非常重要的问题出现了:

当程序发送一段数据时,它究竟经历了什么?

答案就是:

封装与解包

假设我们有这样一段应用数据:

text 复制代码
Hello Linux

数据从应用层向下传输。

每经过一层,该层协议都会增加自己的控制信息。

可以简单理解为:

text 复制代码
应用层:

┌──────────────┐
│ Hello Linux  │
└──────────────┘

        ↓

传输层:

┌──────────┬──────────────┐
│ TCP头部  │ Hello Linux  │
└──────────┴──────────────┘

        ↓

网络层:

┌──────────┬──────────┬──────────────┐
│ IP头部   │ TCP头部  │ Hello Linux  │
└──────────┴──────────┴──────────────┘

        ↓

数据链路层:

┌──────────┬──────────┬──────────┬──────────────┐
│ MAC头部  │ IP头部   │ TCP头部  │ Hello Linux  │
└──────────┴──────────┴──────────┴──────────────┘

这个过程叫:

封装(Encapsulation)

课件将报文概括为:

报文 = 报头 + 有效载荷。


七、不同层的数据为什么叫不同名字?

网络数据在不同层有不同的名称。

所处层次 常见名称
应用层 数据
传输层 Segment / Datagram
网络层 Datagram
数据链路层 Frame

例如:

text 复制代码
应用数据
   ↓
TCP Segment
   ↓
IP Datagram
   ↓
Ethernet Frame
   ↓
物理介质

到达目标主机之后,过程反过来:

text 复制代码
Frame
 ↓
去掉链路层头部
 ↓
Datagram
 ↓
去掉网络层头部
 ↓
Segment
 ↓
去掉传输层头部
 ↓
应用数据

这个过程就是:

解包 / 分用

课件特别强调,学习任何一个网络协议时,都应该首先从宏观上考虑两个问题:

  1. 这个协议是如何解包的?
  2. 它如何把自己的有效载荷交给上层协议?

因为:

理解了解包,也就更容易理解封包。


八、MAC 地址:局域网中的"身份证"

如果两台计算机处于同一个局域网中,它们如何知道数据到底发给谁?

这时候就需要:

MAC 地址

MAC 地址用于识别数据链路层中相连的节点。

课件中给出的特点是:

  • 长度为 48 bit;
  • 即 6 个字节;
  • 通常使用十六进制表示;
  • 常见格式类似:
text 复制代码
08:00:27:03:fb:19

在局域网通信过程中,主机可以根据目标 MAC 地址判断:

这个数据是不是发给我的?


九、IP 地址:解决"跨网络通信"

MAC 地址解决了局域网中的设备识别问题。

但是,如果:

text 复制代码
主机 A

需要和另一个完全不同网络中的:

text 复制代码
主机 B

通信,仅靠 MAC 地址就不够了。

这时候就需要:

IP 地址

IPv4 地址本质上是:

32 位整数

通常使用点分十进制表示:

text 复制代码
192.168.0.1

每一个数字代表一个字节,范围:

text 复制代码
0 ~ 255

十、IP 地址和 MAC 地址到底有什么区别?

这是网络学习过程中非常重要的一组概念。

可以简单理解:

IP 是长期目标,MAC 是下一跳目标。

例如:

text 复制代码
主机 A
  ↓
路由器 R1
  ↓
路由器 R2
  ↓
主机 B

整个过程中:

text 复制代码
目的 IP
────────────────────────────→
最终目标:主机 B

而 MAC 地址则随着一跳一跳的转发发生变化。

课件对此进行了非常重要的总结:

IP 地址在路由过程中具有持续性的目标意义,而 MAC 地址用于下一阶段的局域网转发。

所以:

text 复制代码
IP:我要最终去哪里?

MAC:我这一跳应该交给谁?

十一、数据到达主机还不够:还要找到正确的进程

这里是网络学习中一个非常关键的转折。

假设:

text 复制代码
数据 → 目标主机

是不是就结束了?

答案是:

不是。

因为真正使用数据的是:

text 复制代码
QQ
浏览器
迅雷
服务器程序

这些实际上都是:

进程

所以真正的通信目标不是:

text 复制代码
主机

而是:

text 复制代码
主机上的某一个进程

课件给出了一个非常重要的结论:

数据传输到主机不是目的,而是手段;到达主机内部,再交给目标进程才是真正的目的。

那么问题来了:

操作系统怎么知道应该把数据交给哪个进程?

答案:

端口号


十二、端口号:找到主机里的目标进程

端口号属于传输层协议。

它是一个:

text 复制代码
16 bit

的整数。

端口号的作用就是:

标识主机上的网络进程。

例如:

text 复制代码
IP = 192.168.1.100
Port = 8080

就可以表示:

text 复制代码
192.168.1.100 这台主机上的某一个网络进程

因此:

text 复制代码
IP + Port

可以定位到:

某台主机上的某一个网络进程。


十三、从 IP + Port 理解 Socket

到了这里,我们已经有:

text 复制代码
IP      → 找到主机
Port    → 找到进程

所以:

text 复制代码
IP + Port

就可以理解为一个网络通信端点。

这就是:

Socket

课件进一步将网络通信描述为两个进程之间的通信:

text 复制代码
srcIP
srcPort
dstIP
dstPort

这四个信息共同描述通信双方。

因此可以得到一个非常重要的结论:

网络通信的本质,也是进程间通信。

而:

text 复制代码
IP + Port

可以理解为 Socket 的核心标识。


十四、TCP 和 UDP:两种不同的通信方式

在传输层,我们最常见的两个协议就是:

text 复制代码
TCP
UDP

TCP

TCP 的特点:

text 复制代码
有连接
可靠传输
面向字节流

可以理解为:

我不仅要把数据发出去,还希望能够可靠地传递。


UDP

UDP 的特点:

text 复制代码
无连接
不可靠传输
面向数据报

可以理解为:

我更关注快速发送数据,而不是建立复杂的可靠传输机制。

需要注意的是,这里只是对 TCP 和 UDP 建立一个初步认识,真正理解它们,还需要进一步学习 TCP 的连接管理、可靠性、流量控制、拥塞控制等机制。


十五、网络字节序:为什么网络数据必须统一格式?

在计算机中,多字节数据存在:

text 复制代码
大端
小端

的问题。

例如一个整数在不同 CPU 上可能采用不同的字节存储顺序。

但是网络通信必须解决一个问题:

不同机器的数据表示方式可能不同,怎么办?

TCP/IP 规定:

网络字节序采用大端字节序

也就是说:

所有发送到网络上的数据,都必须按照网络规定的字节序进行处理。

因此在 Linux 网络编程中,我们经常会看到:

c 复制代码
htons()
htonl()

ntohs()
ntohl()

其中:

text 复制代码
h = host
n = network
s = short
l = long

例如:

c 复制代码
htonl()

表示:

host to network long

也就是:

将主机字节序的 32 位整数转换为网络字节序。


十六、进入 Linux 网络编程:Socket API

当我们真正开始写网络程序时,就会接触:

Socket API

最基本的 Socket 接口包括:

c 复制代码
socket()
bind()
listen()
accept()
connect()

其中:

socket()

创建 Socket。

c 复制代码
int socket(int domain, int type, int protocol);

bind()

将地址和端口绑定到 Socket。

c 复制代码
int bind(int socket,
         const struct sockaddr *address,
         socklen_t address_len);

通常服务器需要执行。


listen()

让 TCP 服务器进入监听状态。

c 复制代码
int listen(int socket, int backlog);

accept()

接收客户端连接。

c 复制代码
int accept(int socket,
           struct sockaddr* address,
           socklen_t* address_len);

connect()

客户端主动连接服务器。

c 复制代码
int connect(int sockfd,
            const struct sockaddr *addr,
            socklen_t addrlen);

这些 API 是 Linux Socket 网络编程的基础。


十七、一个最经典的 TCP 通信流程

把前面的知识串起来,一个 TCP 服务器大致可以理解为:

text 复制代码
服务器

socket()
   ↓
bind()
   ↓
listen()
   ↓
accept()
   ↓
read / write
   ↓
close()

客户端:

text 复制代码
socket()
   ↓
connect()
   ↓
read / write
   ↓
close()

可以画成:

text 复制代码
        TCP服务器                    TCP客户端

        socket()                    socket()
            ↓                          ↓
         bind()                    connect()
            ↓                          ↓
        listen() ───────────────→ 建立连接
            ↓
        accept()
            ↓
      数据读写 ←──────────────→ 数据读写
            ↓
         close()                   close()

这样一来,我们就把前面学习的:

text 复制代码
应用层
   ↓
传输层
   ↓
网络层
   ↓
数据链路层
   ↓
物理层

与 Linux 中实际可以调用的:

text 复制代码
socket()
bind()
listen()
accept()
connect()

联系起来了。


十八、sockaddr:Socket API 如何表示地址?

Socket API 是一套比较通用的网络编程接口。

不同协议的地址结构可能不同,因此 Linux 使用:

c 复制代码
struct sockaddr

作为通用接口。

而在 IPv4 网络编程中,我们真正经常使用的是:

c 复制代码
struct sockaddr_in

它主要包含:

text 复制代码
地址类型
端口号
IP地址

课件指出,IPv4 地址使用 sockaddr_in 表示,而 sockaddr_in 中包含地址类型、16 位端口号和 32 位 IP 地址。

所以可以简单理解:

text 复制代码
sockaddr
    ↓
通用地址接口

sockaddr_in
    ↓
IPv4 地址结构

十九、把整篇文章串起来:一次网络通信究竟发生了什么?

现在我们可以把整个过程完整地串起来。

假设:

浏览器访问一个服务器。

首先:

text 复制代码
浏览器

是一个进程。

它需要把数据发送出去。

↓

通过:

text 复制代码
Socket

进入操作系统网络协议栈。

↓

传输层:

text 复制代码
TCP / UDP

负责主机之间的数据传输。

↓

网络层:

text 复制代码
IP

负责寻找目标主机以及进行路由。

↓

数据链路层:

text 复制代码
MAC

负责当前局域网中的数据传输。

↓

物理层:

text 复制代码
网线 / 光纤 / Wi-Fi

最终把数据转换成信号发送出去。

完整过程可以抽象成:

text 复制代码
        应用程序
           │
           ▼
       Socket API
           │
           ▼
       ┌─────────┐
       │ 应用层  │
       ├─────────┤
       │ 传输层  │ ← TCP / UDP / Port
       ├─────────┤
       │ 网络层  │ ← IP / Routing
       ├─────────┤
       │链路层   │ ← MAC / Frame
       ├─────────┤
       │ 物理层  │ ← 网线/Wi-Fi/光纤
       └─────────┘
           │
           ▼
         网络
           │
           ▼
       目标主机
           │
           ▼
       目标进程

这就是整个网络通信的宏观视角。


二十、网络学习最重要的一张"地图"

如果刚开始学习 Linux 网络编程,很容易被大量概念弄得混乱。

其实只需要抓住下面这张关系图:

text 复制代码
                   网络通信
                       │
             ┌─────────┴─────────┐
             │                   │
          主机之间             进程之间
             │                   │
            IP                 Port
             │                   │
             └───────┬───────────┘
                     │
                  Socket
                     │
              TCP / UDP
                     │
                  网络协议栈
                     │
        ┌────────────┼────────────┐
        │            │            │
      应用层       传输层       网络层
                                   │
                                  IP
                                   │
                              数据链路层
                                   │
                                  MAC
                                   │
                                物理层

理解这张图之后,后续学习:

text 复制代码
TCP
UDP
HTTP
DNS
Socket
路由
交换机
网络编程

都会容易很多。


二十一、总结:网络的本质是什么?

学习完这一部分,我们可以用几个问题来总结整个网络体系。

1. 为什么需要网络?

因为不同计算机之间需要:

通信和共享数据。

2. 为什么需要协议?

因为不同计算机之间必须:

遵守共同的通信规则。

3. 为什么协议要分层?

因为:

分层能够模块化、解耦合,降低系统复杂度。

4. MAC 地址解决什么问题?

解决局域网内设备的识别与转发问题。

5. IP 地址解决什么问题?

解决跨网络的主机寻址和路由问题。

6. Port 解决什么问题?

解决一台主机内部不同网络进程的识别问题。

7. Socket 是什么?

可以从网络编程的角度理解为:

网络通信端点。

8. 网络通信的本质是什么?

最终可以归纳为:

不同主机上的不同进程之间进行数据交换。


写在最后

计算机网络刚开始学习时,看起来会充满各种陌生概念:

text 复制代码
MAC
IP
TCP
UDP
Port
Socket
Frame
Segment
Datagram
Router
Switch

但如果把这些概念拆开来看,它们其实并不是孤立存在的。

它们共同解决的是一个问题:

如何让一个主机上的进程,把数据准确地交给另一台主机上的目标进程。

因此,可以把整个网络通信过程浓缩成一句话:

text 复制代码
进程
 ↓
Socket
 ↓
Port
 ↓
TCP/UDP
 ↓
IP
 ↓
MAC
 ↓
物理介质
 ↓
网络
 ↓
目标主机
 ↓
目标Port
 ↓
目标进程

这条链路,就是理解 Linux 网络编程最重要的主线。

当这条主线真正建立起来之后,后面再学习 TCP 三次握手、四次挥手、UDP、HTTP、DNS、路由、NAT、网络抓包以及 Linux Socket 编程,就不再是一个个孤立的知识点,而是在不断填充这张网络知识地图。

而这也正是从"会使用网络"走向"真正理解网络"的开始。


结尾

uu们,本文的内容到这里就全部结束了,道尔在这里再次感谢您的阅读!

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 道尔柯南 C/C++ & Linux 底层探索者 | 一个正在努力学习的技术博主 *** ** * ** *** 👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。 ❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。 ⭐ 【收藏】 把核心知识点存好,在需要时随时查、随时用。 💬 【评论】 分享你的经验或疑问,评论区一起交流避坑! 不要忘记给博主"一键四连"哦! "今日目标达成!" |

结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!

相关推荐
wangbing11251 小时前
开发指南148-WebSocket-后端
网络·websocket·网络协议
Eloudy3 小时前
互联网络设计过程中的一些 PPA 经验原则
网络·互联
国科安芯11 小时前
一颗当两颗用:ASC4T245S 的“两组独立 2 位 + 控制挂靠 VCCA“账
网络·电平转换·抗辐射·在轨服务
冯胤清11 小时前
《Jev-IDS:网络入侵检测一种系统模型》论文深度分析总结
网络
91刘仁德13 小时前
HTTP协议详解:从URL到HTTP服务器的完整实战
服务器·网络·笔记·网络协议·http
Sarapines Programmer13 小时前
【Wireshark】安装与使用指南
网络·测试工具·wireshark
星夜夏空9915 小时前
网络编程(5)—— Reactor实现(v4)
网络
rest102417 小时前
用io_uring进行io测试
网络
恒拓高科WorkPlus17 小时前
企业怎样选择IM即时通讯平台?私有化部署还是SaaS更适合?
网络·github