目录
[1. 计算机网络背景](#1. 计算机网络背景)
[1.1 局域网](#1.1 局域网)
[1.1.2 局域网的组成](#1.1.2 局域网的组成)
[1.2 广域网](#1.2 广域网)
[1.1.2 广域网的组成](#1.1.2 广域网的组成)
[2. 初始网络协议](#2. 初始网络协议)
[2.1 网络协议的定义和作用](#2.1 网络协议的定义和作用)
[2.2 网络协议的分层结构](#2.2 网络协议的分层结构)
[2.2.1 OSI七层模型](#2.2.1 OSI七层模型)
[2.2.2 TCP/IP 五层(四层)模型](#2.2.2 TCP/IP 五层(四层)模型)
[3. 再识网络协议](#3. 再识网络协议)
[3.1 为什么要有 TCP/IP 协议](#3.1 为什么要有 TCP/IP 协议)
[3.2 TCP/IP 协议与操作系统的关系](#3.2 TCP/IP 协议与操作系统的关系)
[4. 网络传输基本流程](#4. 网络传输基本流程)
[4.1 局域网网络传输流程图](#4.1 局域网网络传输流程图)
[4.1.1 认识 MAC 地址](#4.1.1 认识 MAC 地址)
[4.1.2 局域网通信原理(以太网为例)](#4.1.2 局域网通信原理(以太网为例))
[4.1.3 TCP/IP 协议通讯过程](#4.1.3 TCP/IP 协议通讯过程)
[4.1.3.1 网络协议栈](#4.1.3.1 网络协议栈)
[4.1.3.2 数据包封装和分用](#4.1.3.2 数据包封装和分用)
[4.2 跨网络传输流程](#4.2 跨网络传输流程)
[4.2.1 网络种的地址管理 -- 认识 IP 地址](#4.2.1 网络种的地址管理 -- 认识 IP 地址)
[5. Socket 编程预备](#5. Socket 编程预备)
[5.1 认识端口号](#5.1 认识端口号)
[5.2 传输层的典型代表](#5.2 传输层的典型代表)
[5.2.1 简单介绍 TCP 协议和 UDP 协议](#5.2.1 简单介绍 TCP 协议和 UDP 协议)
[5.3 网络字节序](#5.3 网络字节序)
[5.4 socket 编程接口](#5.4 socket 编程接口)
[5.4.1 socket 常见 API](#5.4.1 socket 常见 API)
[5.4.2 sockaddr 结构](#5.4.2 sockaddr 结构)
1. 计算机网络背景
计算机一开始是相互独立的,是用于处理一些数据计算任务的。数据处理的过程一般都需要很多步骤,所以当人使用计算机进行数据的协作处理的时候,就需要进行数据间的传输。但是再没有网络的时代,只能通过人使用软盘在各个计算机之间进行拷贝,效率极低。
为了提高数据信息传输的效率,就产生了网络,使人们能远距离且高效的传输数据信息。
1.1 局域网
局域网(Local Area Network,LAN)是指在某一区域内由多台计算机及相关设备(路由器、交换机)相互连接而成的计算机网络。
1.1.2 局域网的组成
(1)计算机设备:包括服务器和客户端计算机。服务器是局域网中的核心设备,用于存储和管理共享资源,如文件、数据库、打印机等,并为客户端提供服务;客户端计算机是用户直接使用的设备,通过网络连接到服务器获取服务和资源。
(2)网络连接设备 :如交换机、路由器、集线器等。交换机用于连接多台计算机,实现数据帧的转发和交换,提高网络的性能和效率 ;路由器主要用于连接不同的局域网,实现网络之间的数据路由和通信;集线器则将多个计算机连接在一起,形成一个共享的网络环境,但它的性能相对较低。
(3)传输介质:负责在计算机和网络设备之间传输数据,常见的传输介质有双绞线、光纤和无线信号。双绞线成本较低,适用于短距离传输;光纤具有高带宽、低损耗、抗干扰能力强等优点,常用于长距离和高速网络传输;无线信号则为移动设备提供了便捷的网络接入方式,使用户可以在一定范围内自由移动并保持网络连接。

上图左右分别是两个局域网,通过路由器来连接。
1.2 广域网
广域网(Wide Area Network,WAN)是一种覆盖范围广泛的计算机网络,通常用于连接不同城市、地区甚至不同国家的计算机系统和局域网。
1.1.2 广域网的组成
(1)通信子网:主要负责数据的传输和交换,由通信线路和通信设备组成。通信线路包括电话线、光纤、卫星链路等,通信设备有路由器、交换机、调制解调器等。这些设备用于将不同的局域网或计算机连接起来,实现数据在广域范围内的传输。
(2)资源子网:由连接在广域网上的各种计算机系统和终端设备组成,负责提供各种网络资源和服务,如服务器上的文件、数据库、应用程序等,以及用户使用的个人计算机、工作站等终端设备。

上图就是将各个地区的局域网通过路由器连接起来,形成了一个更大的局域网,把这种大的局域网称为广域网。所谓的局域网和广域网只是一个相对的概念。
2. 初始网络协议
2.1 网络协议的定义和作用
协议本质就是一种约定 。网络协议是指为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
网络协议的作用 :如同人类社会中的交通规则或语言规范,网络协议确保了不同设备之间能够准确、高效地进行数据通信。它规定了数据的格式、传输顺序、错误处理方式以及通信双方如何进行交互等内容,使得各种计算机设备和网络系统能够相互理解和协同工作。
2.2 网络协议的分层结构
为了更好的进行模块化以及解耦合,网络协议的设计和实现通常采用分层的体系结构,常见的有 OSI(Open System Interconnection,开放系统互连)七层模型(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)和 TCP/IP 四层模型(网络接口层、网际层、传输层、应用层)。每一层都有其特定的功能和任务,并且通过层与层之间的接口进行通信。例如,物理层负责处理物理介质上的信号传输,数据链路层则负责将物理层接收到的信号转换为数据帧,并进行差错检测和纠正等。
2.2.1 OSI七层模型
OSI(Open System Interconnection,开放系统互连)七层网络模型称为开放式系统互联参考模型,是一个逻辑上的定义和规范。


其实在网络角度,ISO(国际标准化组织) 定义的协议7层模型非常完善,但是在实际操作的过程中,会话层、表示层是不可能接入到操作系统中的,既复杂又不实用,所以在工程实践中,最终落地的 TCP/IP 五层(四层)模型。
2.2.2 TCP/IP 五层(四层)模型
TCP/IP 是一组协议的代名词,它还包括许多协议,组成了 TCP/IP 协议簇。TCP/IP 通讯协议采用了 5 层的层级结构。
(1)应用层: 负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。我们的网络编程主要就是针对应用层。
(2)传输层:负责两台主机之间的数据传输. 如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到目标主机。
(3)网络层: 负责地址管理和路由选择。例如在 IP 协议中, 通过 IP 地址来标识一台主机, 并通过路由表的方式规划出两台主机之间的数据传输的线(路由)。路由器(Router)工作在网路层。
(4)数据链路层: 负责设备之间的数据帧的传送和识别。例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作。有以太网、令牌环网, 无线 LAN 等标准。交换机(Switch)工作在数据链路层。
(5)物理层:负责光/电信号的传递方式。比如现在以太网通用的网线(双绞线)、早期以太网采用的的同轴电缆(现在主要用于有线电视)、光纤, 现在的 wifi 无线网使用电磁波等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等. 集线器(Hub)工作在物理层。

物理层我们考虑的比较少,我们只考虑软件相关的内容。因此很多时候我们直接称为 TCP/IP 四层模型。
3. 再识网络协议
3.1 为什么要有 TCP/IP 协议
首先,即便是单台主机,计算机内部也是存在协议的,比如:其他设备和内存通信,会有内存相关的协议;其他设备和磁盘通信,会有磁盘相关的协议。这些协议都是在本地主机各自的硬件中,通信的成本、问题比较少。
其次,网络通信最大的特点就是主机之间距离变远了。任何通信特征的变化一定会带来新的问题。比如当距离变远了之后,数据在传输的过程中丢失的问题,怎么定位目标主机的问题,怎么等等。
所以TCP/IP 协议本质就是通信主机的距离变远了,为了解决距离变远产生的问题而诞生的解决方案。
3.2 TCP/IP 协议与操作系统的关系

(1)所有主机上的操作系统可以不同,但是主机上的网络协议栈的实现必须按照标准进行相同的实现,这也是不同操作系统的主机可以进行网络通信的原因。
(2)网卡就是网络通信的底层硬件,处于物理层;数据链路层在网卡的驱动程序中进行实现;网络层和传输层被集成在内核中,在操作系统中进行实现;应用层在操作系统之上,由用户进行实现。
(3)整个网络协议栈涉及到硬件、驱动、操作系统以及用户,所以协议一定是需要IT各行各业都进行支持和配合。
(4)传输层最著名的协议就是 TCP,网络层最著名的协议就是 IP,而这两层都处于操作系统中**,网络是操作系统的一部分,所有不同的操作系统在 TCP/IP 的实现上一样**。
**所谓协议,朴素的可以理解为,就是通信双方都认识的结构化数据类型,也就是不同操作系统在网络部分实现时具有相同的网络协议相关的结构体。**当进行网络传输时,发过来的数据能够使用相同的方式进行解析。因为协议栈是分层的,所以每层双方都有协议,同层之间互相可以认识对方的协议。
就像快递单子一样,发货方和收货方都能看懂,约定使用快递单来传递信息,快递单就对应着结构体。
4. 网络传输基本流程
4.1 局域网网络传输流程图
4.1.1 认识 MAC 地址
MAC 地址用来识别数据链路层中相连的节点,长度为 48 位(6字节)。一般用 16 进制数字加冒号的形式来表示(例如:08:00:27:03:fb:19)。
在网卡出厂时就确定了,不能修改。MAC 地址通常是唯一的(虚拟机中的 MAC 地址不是真实的 MAC 地址,可能会冲突;也有些网卡支持用户配置 MAC 地址)。MAC 地址在一个子网中唯一就够用了。
可是使用命令ifconfig进行查看:

4.1.2 局域网通信原理(以太网为例)

如上图所示,当主机 A 向主机 E 发送数据包时,该数据包会被子网中的所有主机所看到,但是当其他主机看到数据包发现目标地址不是自己,就不会进行理会,当主机 E 识别到该数据包是发给自己的,就会进行接收。
(1)以太网中,任何时刻只允许一台机器向网络中发送数据(以太网的本质就是共享的资源)。
(2)如果有多台同时发送,会发生数据干扰,我们称之为数据碰撞(这也是为什么一个子网用的人多了之后网速降低了,因为人多之后,数据碰撞的概率增加了,单位时间发出去的报文就减少了)。
(3)没有交换机的情况下,一个以太网就是一个碰撞域。
(4)所有发送数据的主机要进行碰撞检测和碰撞避免(碰撞检测和碰撞避免用于维持使用该以太网主机的互斥关系)。
(5)局域网通信的过程中,主机对收到的报文确认是否是发给自己的,是通过目标 MAC 地址判定。
4.1.3 TCP/IP 协议通讯过程
4.1.3.1 网络协议栈

如上图所示,两台主机之间进行通信,用户进行网络通信的时候,要贯穿每层的协议,每一台主机从上到下的所有网络协议称为网络协议栈。而所以当进行上述传输流程的时候,每层都要进行封装和解包。如下图所示:

(1)报头:对应协议层的结构体字段。
(2)有效载荷:该数据包传输的有效字段。
(3)报文:报头 + 有效载荷。
明确一下不同层完整报文的叫法:在传输层叫做段(segment), 在网络层叫做数据报(datagram), 在链路层叫做帧(frame)。
知识点1:
任何协议必须要做到以下两点:(a)将有效载荷进行分离。(b)将自己的有效载荷交付给具体的上层协议。知识点2:
在数据链路层,收到报文之后对其进行解包,发现该报文不是发给目标主机的则在数据链路层直接丢弃。
4.1.3.2 数据包封装和分用
如下图所示:自顶向下将报头和有效载荷合在一起的过程叫做封装。

如下图所示:通过网卡接收到数据包之后,自底向上依次解包并传递到上层对应的某一种协议的过程叫做分用。

4.2 跨网络传输流程
4.2.1 网络种的地址管理 -- 认识 IP 地址
IP 协议有两个版本,IPv4 和 IPv6。没有特殊说明,默认都是指的 IPv4。
IP 地址是 IP 协议中,IP 地址是一个 4 字节,32 位的整数; 我们通常也使用 "点分十进制" 的字符串 表示 IP 地址, 例如 192.168.0.1 ; 用点分割的每一个数字表示一个字节, 范围是 0 - 255;
跨网段的主机的数据传输. 数据从一台计算机到另一台计算机传输过程中要经过一个或多个路由器。
下图是一张两台主机跨局域网通信的示意图,路由器也可以近似看作一台主机,目的 IP 地址表示最终的主机地址,而 MAC 地址表示的是当前时刻要去到的下一个节点的地址。

如下图所示,用户 A 和路由器在第一个子网中,用户 B 和路由器在第二个子网中,在同一个子网中,里面主机的 IP 地址前半部分都是相同的,当 IP 为 192.168.2.2 的主机要发送数据给 IP 为 172.168.2.2 的主机时,发现该 IP 地址不属于当前局域网,然后就先给到 IP 为 192.168.2.1 的路由器,然后在路由器中进行 IP 地址的转换,转换为第二个子网中的 IP 地址 172.168.2.1,再传输到目标主机。

结合封装与解包,体现路由器解包和重新封装的特点。如下图所示,在网络层发现不是传给第一个局域网中的主机时,进行 MAC 帧的封装,传给下一个节点(也就是路由器),路由器拿到数据帧之后向上交付对链路报文进行解包,发现对应的目的 IP 地址在第二个子网中,然后向下交付重新封装 MAC 帧,传送给用户 B。
路由的过程中,数据帧中的 IP 地址不变,MAC 地址一直在变,所以 MAC 地址只会在本局域网内有效。

如下图所示,就是跨网络传输的整个宏观的流程图:

IP 网络层存在的意义:提供网络虚拟层, 让世界的所有网络都是 IP 网络,屏蔽最底层网络的差异。
5. Socket 编程预备
5.1 认识端口号
IP 在网络中,用来标识主机的唯一性。
使用网络进行数据的传输并不是目的,是两台主机进行数据交互的手段。但是数据传输到主机是没有用的,要将数据传递到目标进程,让进程使用数据才是目的。所以网络通信的本质就是两台主机中两个进程的进程间通信。
进程是人在系统中的代表,只要把数据给到进程,就相当于人拿到了数据。
但是系统中同时会存在非常多的进程,当数据到达目标主机之后,怎么转发给目标进程呢?这时候就需要引入端口号。
端口号(port)是传输层协议的内容。端口号是一个 2 字节 16位的整数。
一台计算机可能同时运行多个网络应用程序,仅仅依靠 IP 地址只能确定目标计算机,而端口号则用于进一步区分该计算机上的不同应用程序或服务,确保数据能够准确的交付到对应的程序或服务中。
IP 地址 + 端口号 用于标识网络上的某一台主机的某一个进程,一个端口号只能被一个进程占用。

端口号是 16 位的整数:
0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的端口号都是固定的。
1024 - 65535:操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的。
传输层协议(TCP 和 UDP )的数据段中有两个端口号,分别叫做源端口号和目的端口号,描述数据是谁发的和发给谁的。
知识点1:
端口号和进程 PID 都是用于标识进程唯一性的,为什么还要使用端口号。主要是因为不是所以的进程都是网络进程,其次是将网络部分与系统部分进行解耦。比如身份证号(PID)和学号(端口号),当身份证系统进行改变的时候,在学校对于一个学生的标识还是使用的学号,实现了解耦。
另外,一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定。
IP 地址用来标识互联网中唯一的一台主机,port 用来标识该主机上唯一的一个网络进程,所以 IP + port 就能标识互联网中唯一的一个网络进程。IP + port 叫做套接字 socket。
5.2 传输层的典型代表
传输层是属于操作系统内核的,那么要通过网络协议栈进行通信,必定调用的是传输层提供的系统调用来进行的网络通信,如下图所示:

5.2.1 简单介绍 TCP 协议和 UDP 协议
TCP(Transmission Control Protocol 传输控制协议)和 UDP(Transmission Control Protocol 传输控制协议) 都是传输层的协议。
TCP协议的特点:
(1)连接特性:TCP 是面向连接的协议。在数据传输之前,需要在发送方和接收方之间建立一条连接,就像打电话时先拨号建立连接一样。连接建立后,双方才能进行数据传输,传输完成后再释放连接。
(2)可靠性:TCP 提供可靠的数据传输服务。它通过序列号、确认应答、重传机制等保证数据无差错、按顺序到达接收方。如果发送方发送的数据在规定时间内没有收到接收方的确认应答,就会重新发送数据,以确保数据的完整性。
(3)流量控制与拥塞控制:TCP 具有流量控制和拥塞控制机制。流量控制可以防止发送方发送数据过快,导致接收方处理不过来而丢失数据。拥塞控制则是当网络出现拥塞时,通过调整发送方的发送速率,避免网络进一步拥塞,保证网络的稳定性和可靠性。
(4)数据传输单位:TCP 以字节流的方式传输数据,将应用程序交下来的数据看成是一连串的字节流,没有明确的消息边界。接收方在接收数据时,需要根据应用层的协议来解析数据的边界和含义。
UDP协议的特点:
(1)连接特性:UDP 是无连接的协议。发送方在发送数据时不需要与接收方建立连接,就像写信一样,直接将数据报发送出去,不管接收方是否准备好接收。
(2)不可靠性:UDP 不保证数据的可靠传输,它没有确认应答、重传等机制。数据报可能会在传输过程中丢失、重复或乱序到达接收方,但 UDP 也因此具有较低的延迟和较小的开销。
(3)数据传输单位:UDP 以数据报的形式传输数据,每个数据报都是独立的,有明确的边界。UDP 对数据报的长度有一定限制,一般不超过 64KB。
(4)应用场景:UDP 适用于对实时性要求较高,而对数据准确性要求相对较低的应用,如视频会议、在线游戏、音频流等。这些应用可以容忍少量的数据丢失或错误,更注重数据的实时性和流畅性。
5.3 网络字节序
内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端和小端之分,网络数据流同样有大端和小端之分。
发送主机通常发送缓冲区中的数据按内存地址从低到高的顺序发送;接收主机把网络上街道的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存。
因此,网络数据流的地址这样规定:先发出的数据是低地址,后发出的数据是高地址。TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址存高权值位。
如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送。
为了网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

h 表示 host ,n 表示 network,l 表示 32 位长整数,s 表示 16位短整数。
htonl 表示将 32 位长整数从主机字节序转换为网络字节序。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
5.4 socket 编程接口
5.4.1 socket 常见 API
cpp
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
// 开始监听 socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
5.4.2 sockaddr 结构
socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,如 IPv4,IPv6以及 UNIX Domain Socket。
IPv4 和 IPv6 的地址格式定义在netinet/in.h 中,IPv4 地址用 sockaddr_in 结构体表示,包括 16 位地址类型,16 位端口号和 32 位 IP 地址。
IPv4、IPv6 地址类型分别定义为常数 AF_INET、AF_INET6。这样只要取得某种 sockaddr 结构体的首地址,不需要知道具体是哪种类型的 sockaddr 结构体,就可以根据地址类型字段确定结构体中的内容。
地址类型为 AF_UNIX 是用于本地进程通信的结构体。

socket API 可以都用 struct sockaddr *类型表示,在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收 IPv4, IPv6, 以及 UNIX DomainSocket 各种类型的 sockaddr 结构体指针做为参数。
上述就好比 C++ 中,sockaddr 作为基类,而sockaddr_in 和 sockaddr_un 是其子类,是一种 C 风格的继承和多态。