网络基础概念
计算机网络是现代信息世界的基石,但初学时面对一堆术语常感混乱。本篇将以通俗易懂且不失深度的方式,细致整理总结网络中最重要的基本概念,并串联起两台主机通信的完整流程,深入到协议字段和内核行为~~
一、核心角色:客户端与服务器
客户端(Client)
主动发起通信的一方。通常是运行在用户设备上的应用程序。除了我们熟知的浏览器、App,还包括系统更新服务、NTP时间同步客户端等。客户端的特点是:
-
动态端口:发起连接时,操作系统会临时分配一个未被占用的端口号(如 54321),称为"临时端口"。
-
地址不固定:客户端的IP地址可能是动态分配的(DHCP),也可以是内网地址(NAT转换后上网)。
-
主动关闭:通信结束后,通常由客户端先发起关闭连接的请求(TCP四次挥手由客户端先发FIN)。
服务器(Server)
被动等待连接并提供服务的一方。其特点是:
-
监听固定端口 :如 Web 服务器监听 80/443,MySQL 监听 3306。服务程序启动后会调用
bind()和listen()系统调用,让操作系统内核在该端口上等待。 -
高并发模型:一个服务器通常要同时服务成千上万个客户端。单靠一个进程无法处理,因此演化出多进程、多线程、I/O多路复用(select/epoll)等并发模型。
-
反向代理与负载均衡:在实际大型网站中,客户端直接连接的"服务器"往往是Nginx这样的反向代理,真正的应用服务器藏在后端。这也是C/S模型的扩展。
打个比方:客户端像顾客,服务器像餐厅。但餐厅不仅有前台(反向代理),后厨(应用服务器)和前厅是分离的,前台负责接待并转发需求给后厨,这样后厨可以专注做菜,前厅负责应对高流量。
二、地址与标识:IP地址与端口号(深入协议字段)
IP地址
IPv4 地址详解
一个 IPv4 地址共 32 位,通常用点分十进制表示,如 192.168.1.1。实际上它包含两部分:
-
网络号:标识主机所在的网络(子网)。
-
主机号:标识该网络内的具体设备。
如何划分网络号和主机号?靠子网掩码 。例如 255.255.255.0 表示前 24 位是网络号,后 8 位是主机号。无类域间路由(CIDR)记法为 192.168.1.1/24。
特殊IP地址:
-
127.0.0.1:本地环回地址,数据不经过网卡,直接在内核协议栈中转回本机。 -
0.0.0.0:在本机表示所有IP地址,服务器监听0.0.0.0:80意味着接受来自任何网卡的连接。 -
255.255.255.255:受限广播地址,发给同一物理网络中的所有主机。
公网IP与私网IP(NAT)
由于IPv4地址枯竭,家庭和公司内部普遍使用私有地址(如 10.x.x.x、172.16.x.x、192.168.x.x)。内网主机访问公网时,路由器执行 网络地址转换(NAT) :将数据包中的源IP替换为路由器的公网IP,并记录映射表,收到响应后再根据端口转换回内网IP。这就是为什么你查看自己IP是 192.168.1.x,而百度搜IP显示的是另一个公网地址。
IPv6 简介
IPv6 使用 128 位地址,号称能为地球上每一粒沙子分配IP。格式如 2001:0db8:85a3:0000:0000:8a2e:0370:7334,可以省略前导零和连续零块。IPv6 没有了广播,使用组播和任播,同时原生支持IPSec。
端口号
端口号是一个 16 位无符号整数,范围 0~65535。在 TCP/UDP 协议头部中占据 16 位空间(所以最大就是 65535)。
-
知名端口(0-1023):只有 root/管理员权限才能绑定监听。例如 22(SSH)、80(HTTP)、443(HTTPS)。
-
注册端口(1024-49151):分配给特定服务,但普通用户也可绑定。如 3306(MySQL)、5432(PostgreSQL)。
-
动态/私有端口(49152-65535):操作系统自动分配给客户端程序使用。
端口与Socket
网络编程中常说"Socket",它其实是一个五元组:
(源IP, 源端口, 目的IP, 目的端口, 协议)
只要五元组中任一元素不同,就是不同的Socket连接。这就是为什么服务器一个端口(如80)可以同时服务成千上万个客户端------因为客户端的源IP或源端口不同,五元组唯一区分了每条连接。
比喻:IP地址是写字楼地址,端口号是办公室门牌号。但要注意,一栋楼里可能有多个同名的"财务部"(比如多个公司共用大楼),区分它们需要同时知道大楼地址+房间号。在网络中就是 IP + 端口。
三、通信规则:协议与协议分层
协议
协议不仅仅是"约定",在实现上它是定义在RFC(Request for Comments)文档中的结构化字节流规范 。例如 HTTP/1.1 协议规定请求行必须包含方法、URI和版本,以 \r\n 换行。协议通常包含三要素:
-
语法:数据格式、编码、信号电平。
-
语义:控制信息(如状态码200的含义)、差错处理。
-
时序:顺序、速率匹配。
协议分层
我们以实际应用最广的 TCP/IP五层模型(物理层、数据链路层、网络层、传输层、应用层)来详细拆解,并指出每一层的数据单元名称和关键头部字段。
1. 物理层
-
功能:定义物理设备标准,如网线接口形状、电压高低、光波长、无线频率、比特流传输速率。
-
数据单元:比特(bit)。
-
常见设备:中继器、集线器、光纤收发器。
-
不关心:数据内容,只负责把0/1准确传过去。
2. 数据链路层
-
功能 :在相邻节点 之间(同一局域网或点对点链路)提供可靠的数据传输。负责物理寻址 (MAC地址)、差错检测 、流量控制(部分协议)。
-
数据单元:帧(Frame)。
-
协议举例:以太网(Ethernet)、Wi-Fi(802.11)、PPP。
-
以太网帧结构(详细):
-
前导码(7字节+1字节起始定界符):用于时钟同步。
-
目的MAC地址(6字节):下一跳接收设备的物理地址。
-
源MAC地址(6字节):本机出口网卡的物理地址。
-
类型/长度 (2字节):
0x0800表示上层是IPv4,0x0806表示ARP。 -
数据(46-1500字节):来自网络层的IP数据报。
-
帧校验序列FCS(4字节):CRC32校验,接收端计算校验和与尾部对比,不一致则丢弃帧。
-
-
MAC地址 :48位,全球唯一(理论上),通常用十六进制冒号分隔,如
00:1A:2B:3C:4D:5E。前24位是厂商OUI,后24位由厂商分配。
3. 网络层
-
功能 :负责跨网络的路径选择(路由)和逻辑寻址(IP地址)。将数据从源主机通过多个路由器送达目标主机。提供尽力而为的不可靠传输(IPv4)。
-
数据单元:数据报(Datagram),有时称IP包。
-
核心协议:IP(IPv4、IPv6)、ICMP(ping所用)、ARP(地址解析协议,介于链路和网络层)、OSPF/RIP/BGP(路由协议)。
-
IPv4头部关键字段(20字节固定+可选):
-
版本(4位):4或6。
-
首部长度(4位):以4字节为单位,最小5(20字节)。
-
服务类型TOS(8位):用于QoS优先级。
-
总长度(16位):首部+数据的字节数,最大65535。
-
标识、标志、片偏移:用于IP分片重组。
-
生存时间TTL(8位):每经过一个路由器减1,到0丢弃。防止包在网络中死循环。
-
协议 (8位):
6表示TCP,17表示UDP,1表示ICMP。 -
首部校验和(16位):只校验首部,出错丢弃。
-
源IP地址(32位)。
-
目的IP地址(32位)。
-
-
ARP协议工作细节:当主机A(192.168.1.10)想发送数据给同网段主机B(192.168.1.20)时:
-
A查ARP缓存,没有B的MAC。
-
A发送ARP请求广播帧(目的MAC全F),内容:"谁是192.168.1.20?告诉我你的MAC"。
-
B收到后,回复ARP应答单播帧,告知自己的MAC。
-
A将IP数据报封装进帧,目的MAC填B的MAC,发出。
-
4. 传输层
-
功能 :提供端到端(进程到进程)的数据传输服务。可以弥补网络层的不可靠性(如TCP),也可以保持精简(如UDP)。负责分段、流量控制、差错控制、拥塞控制。
-
数据单元:报文段(Segment,TCP)或数据报(Datagram,UDP)。
-
TCP协议深入:
-
面向连接:通信前必须三次握手建立连接。
-
可靠传输:确认应答ACK、超时重传、滑动窗口流量控制。
-
TCP头部关键字段(20字节):
-
源端口、目的端口(各16位)。
-
序列号Seq(32位):标识本报文段发送的数据第一个字节的序号。初始序列号ISN随机生成。
-
确认号Ack(32位):期望收到对方下一个报文段的Seq。
-
数据偏移(4位):TCP首部长度。
-
标志位 (6位):URG、ACK 、PSH、RST、SYN 、FIN。
-
窗口大小(16位):用于流量控制,告知对方还能接收多少字节。
-
校验和(16位):校验首部和数据部分,计算时包含伪首部(取自IP头的源/目的IP)。
-
紧急指针(16位)。
-
-
三次握手简析:
-
客户端 → 服务器:SYN=1, Seq=x
-
服务器 → 客户端:SYN=1, ACK=1, Seq=y, Ack=x+1
-
客户端 → 服务器:ACK=1, Seq=x+1, Ack=y+1
握手过程协商了初始序列号、MSS、窗口大小等参数。
-
-
-
UDP协议:无连接、不可靠,但头部仅8字节(源端口、目的端口、长度、校验和),适合实时应用(语音、视频、DNS查询)。
5. 应用层
-
功能:为应用程序提供网络服务接口。定义具体应用的数据格式和交互逻辑。
-
数据单元:报文(Message)。
-
协议举例:HTTP/HTTPS、FTP、SMTP、DNS、SSH。
-
HTTP/1.1 请求报文结构:
-
请求行:
GET /index.html HTTP/1.1\r\n -
头部字段:
Host: www.example.com\r\n,User-Agent: ...\r\n -
空行:
\r\n -
可选正文:POST请求的数据。
-
-
DNS解析细节 :浏览器访问
www.example.com时,先检查本地hosts和DNS缓存,若无则向本地域名服务器(通常是路由器或运营商)发起递归查询。本地域名服务器可能进行迭代查询:根域名服务器 → .com顶级域服务器 → example.com权威服务器,最终返回IP。
四、封装与分用
封装(Encapsulation)详细过程(以TCP发送为例)
假设应用层要发送一个HTTP响应,大小为3000字节。经过传输层TCP时:
-
传输层封装(分段)
-
TCP根据路径MTU(最大传输单元,通常1500字节减去IP/TCP首部)和MSS(最大分段大小,约1460字节),将3000字节应用数据分成3个TCP段。
-
为每个段添加TCP头部。例如第一个段:Seq=1001,数据长度1460。第二个段:Seq=2461,数据长度1460。第三个段:Seq=3921,数据长度80。
-
将TCP段交给网络层。
-
-
网络层封装
-
IP层收到TCP段后,添加IP头部。此时数据总长度为 20(IP头)+ 20(TCP头)+ 1460(数据)= 1500字节。
-
如果IP包长度超过链路MTU(如以太网1500),且IP头中DF(不分片)标志未设置,则IP层会进行分片 。但现在通常启用路径MTU发现,TCP主动调整MSS避免分片。
-
设置协议字段为6,计算首部校验和,查路由表确定下一跳和出口接口。
-
交给链路层。
-
-
数据链路层封装
-
链路层(如以太网)根据ARP表获取下一跳MAC地址,添加14字节以太网帧头(目的MAC+源MAC+类型),尾部添加4字节FCS校验。
-
如果网络层下发的IP包大于1500字节且不分片,则链路层无法发送,会丢弃并向网络层报告错误(需要MTU发现机制)。
-
-
物理层发送
- 网卡将帧转换为串行比特流,加上物理层编码(如曼彻斯特编码),通过介质传出。
封装的关键点:每一层都认为自己在和对等层通信(逻辑通信),但实际上数据是垂直向下传递,经由物理介质到达对端后再垂直向上分用。
分用(Demultiplexing)详细过程(以服务器接收为例)
服务器网卡收到一串电信号后:
-
物理层与链路层
-
网卡硬件识别前导码,同步时钟,将比特流还原成帧。
-
检查目的MAC地址:若匹配本机MAC或为广播/组播地址,则接收;否则丢弃(混杂模式除外)。
-
计算FCS并与帧尾对比,错误则丢弃帧。
-
剥去帧头帧尾,根据"类型"字段(0x0800)将内层数据(IP数据报)提交给网络层的IP模块。
-
-
网络层分用
-
IP模块检查首部校验和、版本、总长度等。
-
检查目的IP地址是否为本机地址之一(包括环回、广播)。若不匹配且未开启转发,则丢弃;若匹配则继续。
-
查看"协议"字段:值为6,则将IP首部剥离,把内层数据(TCP段)提交给传输层的TCP模块。
-
如果IP数据报是分片后的一个片段,则暂存于缓存,等待所有片段到齐后重组,再交给上层。
-
-
传输层分用
-
TCP模块收到TCP段,检查校验和。
-
根据目的端口查找对应的Socket(即哪个进程在监听该端口)。如果是80端口,找到Web服务器进程的Socket。
-
TCP协议进行可靠性处理:检查序列号、发送确认ACK、重组乱序报文、放入接收缓冲区。
-
当数据连续且完整时,TCP将数据拷贝到进程的用户空间(通过recv系统调用)。
-
-
应用层处理
- Web服务器进程获得完整的HTTP请求报文,解析并生成响应,然后通过同一个Socket调用send将响应数据发回,开始新一轮的封装过程。
分用的精髓在于协议头部中的类型字段 和端口字段,它们起到了"拆包指引"的作用。
五、交互基本单元:请求与响应(再细化)
请求(Request)
以HTTP POST请求为例:
POST /api/login HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: 45
{"username":"alice","password":"123456"}
-
请求行中的方法定义了操作语义:GET(获取)、POST(提交)、PUT(更新)、DELETE(删除)等。
-
头部字段
Content-Length至关重要,它告诉服务器本次请求正文的字节数。TCP是流式协议,没有边界,必须靠这个长度来区分后续字节流中哪部分是本次请求的正文,否则服务器可能无法正确读取。 -
服务器处理完登录请求,可能返回一个包含Session ID的
Set-Cookie头部,让后续请求携带凭证。
响应(Response)
对应响应可能如下:
text
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 30
{"status":"success","token":"xyz"}
-
状态码 :
200 OK表示成功。分类:1xx信息、2xx成功、3xx重定向、4xx客户端错误、5xx服务器错误。 -
状态码
301(永久重定向)和302(临时重定向)配合Location头部,告诉浏览器去新的URL获取资源。SEO优化中常用。
六、串起来:两台主机之间的网络通信完整流程
场景 :家庭电脑(Windows,IP 192.168.1.10,网关 192.168.1.1,浏览器Chrome)访问 Web 服务器(Linux,公网IP 93.184.216.34,监听80端口,网站 example.com)。
第一阶段:地址解析与连接建立
1. 应用层:URL解析与DNS查询
-
用户在Chrome地址栏输入
http://www.example.com回车。 -
浏览器解析URL:协议
http,主机www.example.com,端口默认80。 -
浏览器检查自身DNS缓存?无。检查系统hosts文件?无。
-
调用系统DNS解析函数(
getaddrinfo),向配置的DNS服务器(如8.8.8.8)发起UDP 53端口的DNS查询请求。 -
DNS请求的封装:应用层DNS报文 → UDP段(源端口随机,目的53) → IP数据报(目的IP
8.8.8.8) → 帧(目的MAC为网关192.168.1.1)。 -
经路由器转发后,DNS服务器返回响应,包含
www.example.com的A记录:93.184.216.34。 -
浏览器获得目标IP。
2. 传输层:TCP三次握手
-
浏览器调用系统Socket API,创建TCP套接字:
socket(AF_INET, SOCK_STREAM, 0),连接目标:connect(fd, 93.184.216.34:80)。 -
操作系统内核协议栈开始三次握手(在内存中构建TCP状态控制块TCB):
-
第一次握手 :内核生成初始序列号
Seq=client_isn(随机数,如 123456),SYN标志位置1,构造TCP段,下交IP层。IP层加头:源IP192.168.1.10,目的IP93.184.216.34,协议6。链路层查路由:目标IP非本网段,下一跳为默认网关192.168.1.1,通过ARP获取网关MAC,构造帧发送。 -
数据包经过家庭路由器(NAT转换:源IP变为公网IP,源端口变为路由器分配的新端口,记录NAT表),经互联网路由到达服务器。
-
第二次握手 :服务器TCP模块收到SYN后,如果80端口处于LISTEN状态,则分配TCB,记录对方序列号,回复SYN+ACK段:
Seq=server_isn(如 987654),Ack=123457。 -
数据包经互联网返回,路由器根据NAT表转换目的IP和端口,发给客户端。
-
第三次握手 :客户端收到SYN+ACK,内核检查ACK号合法,回复ACK段:
Seq=123457, Ack=987655,并通知应用层connect调用成功返回,连接进入ESTABLISHED状态。
-
3. 应用层:发送HTTP请求
-
浏览器构造HTTP GET请求报文,调用
send(fd, request_data, ...)。 -
内核将数据拷贝到TCP发送缓冲区。TCP根据MSS和拥塞窗口,将数据分段,封装TCP头(源端口54321,目的端口80,Seq=123457,ACK标志置1,Ack=987655),交给IP层。
-
IP层封装,链路层封装,经物理网络发送。
第二阶段:服务器处理与响应
4. 服务器端接收与分用
-
服务器网卡收到帧,按前述分用流程,最终将TCP段提交给监听80端口的Web服务器进程(例如Nginx的worker进程)。
-
Nginx从Socket中读取数据(
read/recv),由于TCP是流,可能一次read读到了半个请求,或两个请求粘在一起。Nginx根据HTTP协议解析:寻找请求行结束符\r\n,再读头部直到遇到空行,根据Content-Length读取指定长度的正文(GET请求通常没有正文)。 -
Nginx解析请求:方法GET,URI
/,Hostwww.example.com。 -
Nginx根据配置(如
root /var/www/html;),将URI映射到本地文件/var/www/html/index.html。
5. 服务器生成响应
-
Nginx检查文件是否存在,权限是否足够。若存在,通过
open和read系统调用读取文件内容(假设是一个简单的HTML文本)。 -
Nginx构造HTTP响应头:
HTTP/1.1 200 OK,Content-Type: text/html,Content-Length: <文件大小>,以及其他头部(如Connection: keep-alive)。 -
调用
send将响应头和文件内容数据写入Socket。内核TCP层将数据分段并发送。
第三阶段:响应返回与渲染
6. 响应路径上的封装与NAT
-
服务器发出的IP数据报:源IP
93.184.216.34,目的IP为家庭路由器的公网IP(假设为1.2.3.4),源端口80,目的端口为NAT映射后的端口(如 12345)。 -
数据包经互联网路由,到达家庭路由器。
-
路由器查NAT表:公网端口12345对应内网
192.168.1.10:54321。路由器修改目的IP为192.168.1.10,目的端口为54321,并重新计算IP校验和,转发到内网。
7. 客户端接收与渲染
-
客户端内核收到响应帧,逐层分用,将TCP数据段放入Socket接收缓冲区,应用层
recv返回HTTP响应数据。 -
浏览器解析HTTP响应头,看到
Content-Type: text/html,开始解析HTML内容。 -
HTML中可能引用外部CSS、JS、图片资源。浏览器解析到
<img src="/logo.png">时,会再次发起新的HTTP请求(通常复用已有的TCP连接,如果Connection: keep-alive),重复上述流程获取资源。 -
浏览器完成渲染,呈现网页。
8. 连接关闭
-
若HTTP头部包含
Connection: close,服务器发送完响应后会主动关闭连接(发送FIN)。 -
客户端收到FIN后也发送FIN,经过四次挥手关闭TCP连接。
-
若
Connection: keep-alive,连接将保持一段时间,供后续请求复用,减少握手开销。
总结
| 概念 | 核心作用 | 在本次通信中的实际体现 |
|---|---|---|
| IP地址 | 标识网络主机 | 客户端内网IP 192.168.1.10,服务器公网IP 93.184.216.34 |
| 端口号 | 标识主机进程 | 客户端临时端口 54321,服务器监听端口 80 |
| 协议 | 通信规则约定 | HTTP定义请求响应格式,TCP保证可靠传输,IP负责寻址 |
| 协议分层 | 解耦复杂度 | 五层模型:应用层(HTTP) → 传输层(TCP) → 网络层(IP) → 链路层(以太网) → 物理层 |
| 封装 | 自上而下添加头部 | HTTP报文 → TCP段(端口) → IP包(IP地址) → 以太网帧(MAC) |
| 分用 | 自下而上剥离头部并分发 | 网卡收帧 → IP层根据协议号交TCP → TCP根据端口交Web服务器 |
| 客户端/服务器 | 主动请求方 / 被动响应方 | Chrome浏览器(客户端)主动连接 Nginx(服务器) |
| 请求/响应 | 一次通信的基本对话单元 | GET / HTTP/1.1 → HTTP/1.1 200 OK + HTML 内容 |
扩展
| 步骤 | 典型耗时 | 原因 |
|---|---|---|
| DNS解析 | 10~100ms | 可能有多级递归,受DNS服务器远近影响 |
| TCP握手 | 1个RTT(约20~200ms) | 与服务器物理距离相关 |
| 发送请求 | 几十μs + 网络传输 | 取决于带宽和延迟 |
| 服务器处理 | 几ms ~ 几秒 | 取决于业务逻辑和数据库查询 |
| 响应传输 | 类似请求 | 受带宽和内容大小影响 |
| 浏览器渲染 | 几十ms ~ 数秒 | JS/CSS解析执行,布局绘制 |
理解这些底层细节后,再去分析网络故障(如为什么连接超时?为什么网页打开慢?)便会游刃有余。网络世界虽复杂,但分层与封装分用的思想是贯穿始终的钥匙~~~以上就是本篇文章的全部内容啦~~咱们下篇再见~