承渊政道头像
关注
Linux网络学习【⽹络基础概念】封面图

Linux网络学习【⽹络基础概念】

🔥承渊政道:个人主页

❄️个人专栏: 《C语言基础语法知识》 《数据结构与算法》 《C++知识内容》 《Linux系统与网络知识》 《算法刷题指南》 《测评文章活动推广》 《大模型语言路线学习》 《MySQL数据库学习》 《Python知识内容》 《cpolar知识学习》

✨逆境不吐心中苦,顺境不忘来时路!✨
🎬 博主简介:

在Linux系统学习中,网络基础是系统编程、网络编程以及服务器开发必须掌握的一块核心知识.很多看似简单的操作,例如访问网页、远程登录服务器、发送请求、传输文件,本质上都依赖底层网络协议、地址体系以及不同网络设备之间的协同工作.只有先建立起完整的网络认知,后续学习Socket、TCP/UDP、HTTP以及高并发网络服务器时,才不会停留在“会调用接口”的层面.网络知识涉及的概念比较多,例如:网络是如何构成的?局域网和广域网有什么区别?IP 地址、MAC地址和端口号分别解决什么问题?路由器、交换机、网关各自承担什么职责?数据从一台主机发送到另一台主机时,又经历了哪些封装、转发与解析过程? 这些内容共同构成了理解计算机网络运行机制的基础.本文将围绕 Linux 网络基础概念 展开,从网络的基本组成入手,逐步介绍网络分层模型、常见网络协议、IP 地址与子网、端口与套接字、网络设备以及数据传输的基本流程,并结合 Linux 环境帮助大家理解这些概念在实际系统中的作用.通过本文的学习,你将能够建立一套较为完整的计算机网络基础框架,理解数据在网络中的传输逻辑以及各层协议之间的协作关系,为后续学习 TCP/IP、Socket 网络编程、Linux 网络通信、HTTP 协议以及高并发服务器开发 打下扎实基础.


一、⽹络基础概念


网络基础概念可以简单理解为:把多台计算机或其他设备连接起来,让它们之间能够进行数据传输和资源共享.

早期的计算机通常是独立工作的,每台计算机都有自己的数据和程序,彼此之间很难交换信息.随着计算机数量增加,人们希望能够共享文件、打印机、服务器等资源,于是就通过通信线路和网络设备把计算机连接起来,逐渐形成了计算机网络.

在计算机网络中,常见的设备有交换机和路由器.交换机主要负责连接同一网络中的多台设备,比如一个办公室里的电脑;路由器则主要负责连接不同的网络,让数据能够从一个网络传输到另一个网络.

按照网络覆盖范围,可以把网络大致分为局域网 LAN和广域网 WAN.局域网的范围比较小,比如家庭、学校、公司内部的网络;广域网的范围更大,可以连接不同城市甚至不同国家的网络.我们每天使用的互联网 Internet,就可以看作一个连接了大量不同网络的超大型网络.

所以,计算机网络的核心作用主要有三个:数据通信、资源共享和协同工作.它让原本彼此独立的计算机能够相互连接,也为后来的互联网、云计算和各种网络应用提供了基础.


1.1计算机网络发展背景





二、初识协议


协议(Protocol),简单来说,就是计算机之间进行通信时,双方共同遵守的一套规则.

两台计算机即使已经通过网线、光纤或者无线网络连接起来,也不代表它们一定能够正确理解对方发送的信息.就像人与人交流一样,只有双方使用相同的语言和交流规则,信息才能准确传递.

在网络通信中,协议主要规定几个方面:发送什么内容、数据采用什么格式、按照什么顺序发送,以及出现错误时应该怎么处理. 只有通信双方都遵守相同的协议,数据才能被正确发送、接收和理解.

例如,我们访问网页时会使用 HTTP/HTTPS 协议;发送电子邮件会使用 SMTP 等协议;而计算机在互联网中进行数据传输时,常用的是TCP/IP 协议族.

所以可以把协议理解为:协议就是计算机之间通信的“共同语言和规则”.

从专业角度来看,网络协议通常包含三个基本要素:语法、语义和同步(时序).语法规定数据“长什么样”,语义规定数据“代表什么意思”,同步则规定数据“什么时候发、按照什么顺序发”.

计算机之间的传输媒介是光信号和电信号.通过 “频率” 和 “强弱” 来表示0和1这样的信息. 要想传递各种不同的信息, 就需要约定好双⽅的数据格式.

思考: 只要通信的两台主机, 约定好协议就可以了么?
定好协议,但是你⽤频率表示01,我⽤强弱表示01,就好⽐我⽤中国话,你⽤葡萄⽛语⼀样,虽然⼤家可能遵守的⼀套通信规则,但是语⾔不同,即是订好了基本的协议,也是⽆法正常通信的.

所以,完善的协议,需要更多更细致的规定,并让参与的⼈都要遵守.计算机⽣产⼚商有很多;计算机操作系统,也有很多;计算机⽹络硬件设备,还是有很多;如何让这些不同⼚商之间⽣产的计算机能够相互顺畅的通信?就需要有⼈站出来, 约定⼀个共同的标准⼤家都来遵守,这就是⽹络协议.


2.1协议分层的好处


协议分层,就是把一个复杂的网络通信过程拆分成多个层次,每一层只负责自己的一部分功能,并通过规定好的接口与相邻层配合.

可以把它类比成人与人打电话.上面的“语言层”负责双方使用什么语言交流,比如汉语或英语;下面的“通信设备层”负责具体怎么把声音传过去,比如使用电话、无线电等设备.两层各自完成自己的任务.

这样设计最大的好处是:各层之间相对独立.比如把电话换成无线电,只需要改变通信设备这一层,上面的汉语交流方式可以不变;反过来,如果把汉语换成英语,下面仍然可以继续使用电话通信.也就是说,某一层发生变化时,通常不需要把整个系统全部重新设计.

因此,协议分层主要有几个优点:能够把复杂问题拆成简单问题,降低网络设计的复杂度;每一层可以独立开发、修改和升级,便于维护;各层使用统一的接口和标准,不同厂商的设备也可以相互通信;同时,相同的功能还可以重复使用,提高开发效率.

一句话概括就是:协议分层就是“各层各司其职,通过标准接口协同工作”,从而让网络系统更容易设计、维护、升级和扩展.


2.2OSI七层模型


OSI 七层模型,全称是开放式系统互联参考模型(Open Systems Interconnection).它的作用,是把复杂的网络通信过程划分成7个层次,让每一层只负责一类任务,各层之间通过接口相互配合.

从上到下分别是:

  1. 应用层:直接为用户和应用程序提供网络服务,比如网页访问、电子邮件、文件传输等.
  2. 表示层:负责数据格式的转换,也会处理编码、压缩、加密等问题,让通信双方能够“看懂”数据.
  3. 会话层:负责建立、管理和结束通信会话,可以理解为管理双方“什么时候开始交流、保持多久、什么时候结束”.
  4. 传输层:负责端到端的数据传输,关注数据是否完整、是否按顺序到达.常见协议有 TCP、UDP.
  5. 网络层:负责逻辑地址和路由选择,也就是决定数据应该经过哪条路径到达目标设备,典型代表是 IP.
  6. 数据链路层:负责相邻设备之间的数据传输,把数据组织成“帧”,并通过 MAC 地址识别设备,交换机主要工作在这一层.
  7. 物理层:位于最底层,负责真正传输0和1,把比特转换成电信号、光信号或无线信号,通过网线、光纤等介质发送出去.

可以把整个通信过程理解成:发送数据时,从应用层一层一层向下封装,最后通过物理层发送;接收数据时,再从物理层一层一层向上解封装,最终交给应用程序.

一句话记忆:上三层面向应用,下四层面向传输;越往下,越接近真实的网络设备和传输介质.

OSI 七层模型最大的意义,并不是说现实网络一定严格按照七层实现,而是它提供了一个非常清晰的分析框架,方便我们理解网络协议、定位网络故障,以及学习TCP/IP等实际网络体系.


2.3TCP/IP五层(或四层)模型

TCP/IP是⼀组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇.

TCP/IP通讯协议采⽤了5层的层级结构,每⼀层都呼叫它的下⼀层所提供的⽹络来完成⾃⼰的需求.

  • 物理层: 负责光/电信号的传递⽅式. ⽐如现在以太⽹通⽤的⽹线(双绞 线)、早期以太⽹采⽤的的同轴电缆(现在主要⽤于有线电视)、光纤, 现在的wifi⽆线⽹使⽤电磁波等都属于物理层的概念.物理层的能⼒决定了最⼤传输速率、传输距离、抗⼲扰性等. 集线器(Hub)⼯作在物理层.
  • 数据链路层: 负责设备之间的数据帧的传送和识别.例如⽹卡设备的驱动、帧同步(就是说从⽹线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就⾃动重发)、数据差错校验等⼯作.有以太⽹、令牌环⽹, ⽆线LAN等标准.交换机(Switch)⼯作在数据链路层.
  • ⽹络层: 负责地址管理和路由选择.例如在IP协议中,通过IP地址来标识⼀台主机,并通过路由表的⽅式规划出两台主机之间的数据传输的线路(路由). 路由器(Router)⼯作在⽹路层.
  • 传输层: 负责两台主机之间的数据传输. 如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到⽬标主机.
  • 应⽤层: 负责应⽤程序间沟通,如简单电⼦邮件传输(SMTP)、⽂件传输协议(FTP)、⽹络远程访问协议(Telnet)等.我们的⽹络编程主要就是针对应⽤层.


物理层我们考虑的⽐较少,我们只考虑软件相关的内容.因此很多时候我们直接称为TCP/IP四层模型.⼀般⽽⾔对于⼀台主机,它的操作系统内核实现了从传输层到物理层的内容;对于⼀台路由器,它实现了从⽹络层到物理层;对于⼀台交换机,它实现了从数据链路层到物理层;对于集线器,它只实现了物理层;但是并不绝对.很多交换机也实现了⽹络层的转发;很多路由器也实现了部分传输层的内容(⽐如端⼝转发).


三、再识协议

3.1为什么要有TCP/IP协议?


为什么要有 TCP/IP 协议? 核心原因是:当计算机从“单机工作”发展到“跨网络、远距离通信”之后,通信环境变得复杂了,必须有一套大家共同遵守的规则.

在一台计算机内部,其实本身就存在很多协议.比如内存之间有自己的通信规则,硬盘与主机之间也有 SATA、SCSI 等接口协议.但这些通信都发生在本机内部,距离很短、环境比较固定,因此问题相对简单.

可是当两台计算机隔得很远,中间还可能经过交换机、路由器以及多个不同的网络时,就会出现很多新的问题.比如:怎么找到目标计算机?数据应该走哪条路?数据太大怎么拆分?传输过程中丢失或出错怎么办?收到数据以后应该交给哪个应用程序?不同厂商、不同操作系统的计算机又怎么互相通信?

TCP/IP 就是为了解决这些问题而形成的一整套网络通信协议.严格来说,TCP/IP 不是一个单独的协议,而是一套协议族.

其中,IP 协议主要负责地址和路由,可以理解为解决“数据要送到哪里、怎么走过去”的问题;TCP 协议主要负责可靠传输,比如数据丢失以后重新发送、保证数据按顺序到达;而在 TCP/IP协议体系中,还有 HTTP、DNS、UDP 等很多协议,各自负责不同的网络功能.

因此,有了TCP/IP之后,不同品牌、不同操作系统、位于不同网络中的计算机,就可以按照统一的规则进行通信.

可以把它类比成寄快递:IP 地址相当于收件地址,路由器负责选择运输路线,数据包就像一个个快递包裹,而TCP会检查包裹是不是都到了、有没有丢失.

一句话总结:TCP/IP 的本质,就是为计算机跨设备、跨网络、远距离通信建立一套统一的规则,让数据能够找到目标、正确传输,并最终交给对应的应用程序.


3.2什么是TCP/IP协议?

TCP/IP 协议不是一个单独的协议,而是一整套用于计算机网络通信的协议族.它规定了不同设备之间如何发送、传输、寻址和接收数据,是互联网最核心的通信基础.

简单理解,可以把 TCP/IP 看成计算机上网时共同遵守的一套“交通规则”.

其中最核心的两个协议是:

  • IP(Internet Protocol,网际协议):负责给设备分配逻辑地址,并决定数据应该经过哪些网络到达目标.可以理解为解决“送到哪里、走哪条路”的问题.
  • TCP(Transmission Control Protocol,传输控制协议):负责可靠地传输数据,保证数据尽量不丢失、不重复,并按照正确顺序交给接收方.可以理解为解决“怎么可靠地送到”的问题.

除了TCP和IP,TCP/IP协议族中还包含很多其他协议,比如 HTTP、HTTPS、DNS、UDP、ICMP、FTP、SMTP 等,它们分别负责网页访问、域名解析、数据传输、网络诊断、文件传输、邮件发送等功能.

如果用一个简单的例子来理解:你访问一个网站时,DNS 先帮你找到网站对应的IP地址,IP 负责把数据送到目标主机,TCP 负责保证数据可靠传输,HTTP/HTTPS 则负责浏览器和网站服务器之间具体交换网页内容.

所以一句话概括就是:TCP/IP是互联网中不同计算机之间进行通信所遵守的一整套标准规则.


3.3TCP/IP协议与操作系统的关系


3.4到底什么是协议?


协议(Protocol),本质上就是通信双方为了能够正确交换信息,而共同遵守的一套规则和约定.

可以先从人与人交流来理解.两个人如果都使用中文,并且都知道一句话应该怎么表达、怎么理解,就能够顺利交流.计算机也是一样:主机A发送一段数据给主机B,B必须知道这段数据是什么格式、每一部分代表什么意思、按照什么顺序处理,否则即使数据成功传过去了,B也可能无法理解.

因此,一个网络协议通常会规定几个方面:数据采用什么格式、各字段表示什么含义、通信按照什么顺序进行,以及发生错误时如何处理.

比如我们约定发送的数据结构中,第一个整数表示 a,第二个表示 b,第三个表示 c.主机 A 发送:

10、20、30

如果主机 B 也遵守同样的约定,那么它就知道:

  • a = 10
  • b = 20
  • c = 30

这说明双方对数据有了共同的理解.

不过需要注意,“结构体就是协议”只是帮助理解的类比,并不完全准确.结构体主要体现的是协议中的数据格式,真正的协议还会规定什么时候发送、谁先发送、收到以后如何应答、出错怎么办等一整套通信规则.

网络协议通常还是分层的.例如应用层有 HTTP、DNS,传输层有 TCP、UDP,网络层有 IP.通信双方在相同层次上遵循相同的协议标准,因此即使一台计算机使用 Windows,另一台使用 Linux,只要双方都正确实现了TCP/IP,就能够进行通信.

所以可以用一句话总结:协议就是通信双方共同遵守的“语言 + 格式 + 流程规则”.

也正因为有统一的协议,不同操作系统、不同厂商、不同设备之间才能真正实现互联互通.


四、⽹络传输基本流程

网络传输基本流程,可以理解为:数据从发送方产生之后,经过一层一层的封装,通过网络传输到接收方,再一层一层地解封装,最终交给对应的应用程序.比如,主机A要给主机B发送一段数据,整个过程大致如下:

  1. 应用层产生数据
    用户通过浏览器、聊天软件、邮件程序等产生需要发送的数据.

  2. 传输层处理数据
    TCP 或 UDP 会对数据进行处理.
    例如 TCP 会把较大的数据拆成多个小段,并加入端口号等信息,用来确定数据最终应该交给哪个应用程序.

  3. 网络层添加 IP 信息
    IP 协议会加入源 IP 地址和目标 IP 地址.
    这一层主要解决:数据要发送给哪台主机,以及应该经过哪些网络到达目标.

  4. 数据链路层封装成数据帧
    再加入MAC地址等信息,把数据组织成“帧”,用于当前局域网中的传输.

  5. 物理层真正发送数据
    最后把数据转换成 0 和 1 对应的电信号、光信号或无线信号,通过网线、光纤或 Wi-Fi 发送出去.

数据在网络中可能会经过多个交换机和路由器.其中交换机主要负责局域网内部的数据转发,路由器则根据目标IP地址,把数据从一个网络转发到另一个网络.

当数据到达主机B后,会进行相反的过程:物理层 → 数据链路层 → 网络层 → 传输层 → 应用层

每一层都会去掉自己对应的信息,并检查和处理数据,这个过程叫做解封装.最后,原始数据被交给主机B中对应的应用程序.

可以把整个过程简单记成:
发送端:数据 → 段 → 包 → 帧 → 比特流
接收端:比特流 → 帧 → 包 → 段 → 数据

所以,网络传输最核心的过程就是:发送端逐层封装 → 网络中转发 → 接收端逐层解封装.


4.1局域⽹络传输流程图


①局域⽹通信原理(以太⽹为例)


局域网通信,以以太网为例,本质上就是:主机先确定目标设备的MAC地址,再把数据封装成以太网帧,通过交换机转发给目标主机.

假设主机A要给主机B发送数据,并且A、B在同一个局域网中.

首先,主机A会根据 IP 地址和子网掩码判断主机B是否和自己处于同一个网段.如果是同一个网段,就可以直接在局域网内通信,不需要经过路由器.

接下来,A虽然知道B的 IP 地址,但以太网真正转发数据时需要的是MAC地址.如果A不知道B的MAC地址,就会使用ARP 协议发送一个广播请求:“谁是 192.168.1.20?请把你的 MAC 地址告诉我。”

同一个局域网中的设备都会收到这个广播,但只有主机B会回应,并告诉A自己的MAC地址.A得到后通常会把这个对应关系暂时保存到 ARP 缓存中.

知道目标MAC地址后,主机A开始对数据进行逐层封装.应用层先产生数据;传输层加入TCP或UDP等信息以及端口号;网络层加入源IP和目标IP;数据链路层再加入源MAC、目标 MAC等信息,把数据封装成一个以太网帧;最后物理层把这些数据转换成电信号、光信号或无线信号发送出去.

以太网帧可以简单理解为:目标 MAC + 源 MAC + 类型 + 数据 + FCS 校验信息

数据到达交换机后,交换机主要看帧中的目标 MAC 地址.交换机会维护一张 MAC 地址表,记录“哪个 MAC 地址位于哪个端口”.如果它已经知道主机B所在端口,就只把帧转发到那个端口.

如果交换机暂时不知道目标MAC在哪个端口,它会进行未知单播泛洪,把帧发送到除来源端口之外的相关端口;同时交换机也会根据收到帧的源 MAC 地址学习设备所在端口.

主机B收到数据后,就开始进行相反的过程,也就是逐层解封装.数据链路层检查目标 MAC 和 FCS;网络层检查目标IP;传输层根据端口号把数据交给相应的应用程序;最后应用程序得到主机A发送的原始数据.

所以整个过程可以简单记成:判断是否同网段 → ARP 获取目标 MAC → 逐层封装 → 交换机按 MAC 转发 → 接收端逐层解封装 → 交给应用程序

其中有一个非常重要的区别:IP 地址主要解决“我要找哪台主机”,MAC 地址主要解决“在当前局域网这一跳交给谁”.

如果目标主机不在同一个局域网,这时主机不会直接获取远程主机的MAC地址,而是获取默认网关的 MAC 地址,先把以太网帧发送给路由器,再由路由器继续转发到其他网络.

一句话总结:在以太网局域网中,主机通过ARP找到下一跳的MAC地址,把数据封装成以太网帧,再由交换机根据 MAC 地址完成局域网内的转发.


②认识MAC地址





MAC地址(Media Access Control Address),可以理解为网卡或网络接口在局域网中的“身份标识”.在以太网通信中,交换机主要依靠MAC地址来判断一帧数据应该转发给哪台设备.

常见的MAC地址长度是 48bit,也就是6字节,通常用十六进制表示,例如:

08:00:27:D3:1B:19

一台计算机可能有多个网络接口,比如有线网卡、无线网卡,每个接口都可以拥有自己的 MAC 地址.MAC地址通常由网卡厂商预设,但现代操作系统也可以对MAC地址进行修改或随机化,所以它并不是绝对永久不变的.

当两台主机位于同一个局域网时,虽然应用通常知道对方的 IP 地址,但以太网真正发送数据帧时还需要知道对方的 MAC 地址.这时就会用到 ARP 协议.

例如,主机A知道主机B的 IP 是 192.168.1.20,但不知道它的MAC地址.主机A会在局域网中发送 ARP 广播:“谁是 192.168.1.20?请告诉我你的 MAC 地址。”

局域网中的设备都会收到这个请求,但主机B发现询问的是自己,就会回复自己的MAC地址.主机A得到以后,会暂时记录在 ARP 缓存中,然后把数据封装成以太网帧发送出去.

在发送过程中,数据会逐层封装:应用数据 → TCP/UDP 报文 → IP 数据包 → 以太网帧 → 比特流

其中,到了数据链路层,会在数据前面加入源MAC地址和目标MAC地址.交换机收到以太网帧以后,会查看目标MAC地址,并根据自己的 MAC 地址表把数据转发到正确的端口.

接收端则进行相反的过程:比特流 → 以太网帧 → IP 数据包 → TCP/UDP 数据 → 应用数据

所以,MAC 地址和 IP 地址虽然都可以用来“标识设备”,但作用不一样:

IP 地址主要用于网络层,负责跨网络寻址和路由;
MAC 地址主要用于数据链路层,负责当前局域网或当前一跳中的帧传输.

尤其要注意:如果目标主机不在同一个局域网,发送方通常不会去获取远程主机的 MAC 地址,而是获取默认网关的 MAC 地址,先把数据帧交给路由器.

一句话总结:IP 地址解决“数据最终要去哪里”,MAC地址解决“这一跳的数据帧具体交给谁”.

因此,在以太网局域网中,可以简单记成:ARP找MAC,交换机看MAC,路由器看IP.


③数据包封装和分⽤





数据包的封装和分用,描述的是数据在网络协议栈中,发送时怎样一层一层加上控制信息,接收时又怎样根据这些控制信息找到正确的上层协议和应用程序.

一、什么是数据封装?
当应用程序要发送数据时,数据会从协议栈的上层逐步向下传递.每经过一层,这一层都会在原有数据基础上加入自己的协议控制信息,这个过程就叫“封装”.

例如主机 A 的应用程序要发送一段“你好”:

应用层首先产生原始的用户数据.

到了传输层,TCP会在应用数据前加入 TCP 首部,其中包含源端口、目的端口、序号、确认号等信息.此时形成一个 TCP 报文段(Segment).

接着进入网络层,IP再加入 IP首部,其中包含源IP地址、目的IP地址、协议号等信息,形成 IP 数据报(Packet / Datagram).

然后进入数据链路层.以以太网为例,会加入以太网首部,包括源MAC、目的MAC、类型字段等,并在尾部加入FCS校验信息,最终形成一个 以太网帧(Frame).

最后到了物理层,网卡把这些数据转换成一串 0 和 1 的比特流,再转换成电信号、光信号或无线信号发送出去.

因此可以简单记成:应用数据 → TCP/UDP 数据 → IP 数据报 → 以太网帧 → 比特流

封装的核心思想就是:上层的数据成为下层的有效载荷,下层再给它加上自己的控制信息.

二、什么是数据分用?
数据到达接收端以后,会按照相反的方向,从下往上进行处理.

这里除了“解封装”之外,还有一个很重要的概念叫 分用(Demultiplexing).

分用就是根据协议首部中的关键字段,判断数据应该交给哪个上层协议或者哪个应用程序.

例如,一个以太网帧到达主机 B:

  1. 数据链路层查看以太网首部中的 EtherType 类型字段.
    如果是 0x0800,说明里面是 IPv4;如果是 0x0806,说明是ARP.于是把有效载荷交给对应协议.

  2. 网络层收到 IP 数据报后,查看IP首部中的 Protocol 协议字段.
    例如 6 表示TCP,17 表示UDP,1 表示ICMP.根据这个字段继续向上传递.

  3. 传输层收到TCP或UDP数据以后,再查看目的端口号.
    例如目的端口是80,就可能交给Web服务;目的端口是53,则可能交给DNS服务.

最终,数据被送到正确的应用程序.

所以:封装解决的是“发送时怎么逐层加信息”;分用解决的是“接收时应该交给谁”。

三、举一个完整例子
假设浏览器要向服务器发送一个 HTTP 请求.

发送时:

HTTP 数据
↓ TCP 加入端口等信息
↓ IP 加入源 IP、目的 IP
↓ 以太网加入源 MAC、目的 MAC
↓ 网卡发送比特流

服务器收到以后:

比特流
↓ 恢复成以太网帧
↓ 根据 EtherType 交给 IP
↓ IP 根据 Protocol 字段交给 TCP
↓ TCP 根据目的端口交给 Web 服务
↓ Web 服务得到 HTTP 请求

这就是一次完整的封装、传输、解封装和分用过程.

一句话总结:发送端逐层封装:不断添加协议首部;接收端逐层分用:根据首部字段把数据准确交给对应的上层协议和应用程序。

可以再简单记成一句:封装是“打包贴标签”,分用是“看标签找收件人”。


4.2跨⽹络传输流程图


跨网络传输,就是数据从一台主机出发,经过一个或多个路由器,跨越不同的局域网或运营商网络,最终到达另一个网络中的目标主机.

假设主机A的IP是 192.168.1.10,要访问外网服务器 203.0.113.100.整个过程可以这样理解:

  1. 主机 A 先判断目标是否和自己在同一个网段.
    主机 A 根据自己的 IP 地址和子网掩码判断后,发现 203.0.113.100 不在本地局域网,因此不能直接把数据发送给目标服务器,而是要先交给自己的默认网关.

  2. 主机 A 找到默认网关的 MAC 地址。
    在以太网中,真正发送数据帧需要MAC地址.所以主机A会通过 ARP 查询默认网关的 MAC 地址,然后把数据封装成以太网帧.
    此时可以简单理解为:

    • 目标 IP:远程服务器的 IP
    • 目标 MAC:默认网关的 MAC

    这里非常重要:虽然最终目标是远程服务器,但当前这一跳的数据帧是先发给路由器的.

  3. 路由器收到数据后进行转发。
    默认网关收到以太网帧后,会去掉原来的数据链路层首部,取出里面的 IP 数据报.然后查看目的IP地址,查询自己的路由表,决定下一步应该把数据发到哪个网络、哪个下一跳路由器.

    接下来,路由器会重新给这个 IP 数据报加上新的数据链路层首部,再发送出去.

  4. 数据可能经过多个路由器。
    每经过一个路由器,都会经历类似的过程:收到数据帧 → 去掉链路层首部 → 查看目的 IP → 查路由表 → 选择下一跳 → 重新封装新的数据帧 → 发出去

    所以,MAC 地址是逐跳变化的。因为每一段链路的发送方和接收方都不同.

    而在不考虑 NAT 等地址转换机制的情况下,源 IP 和目的 IP 通常保持端到端不变.也就是:源 IP 一直是主机 A;目的 IP 一直是目标服务器

  5. 到达目标网络后,最后一个路由器找到目标主机。
    当数据来到目标服务器所在的局域网时,最后一个路由器会通过 ARP 获取目标服务器的 MAC 地址,然后把 IP 数据报重新封装成以太网帧,最终发送给服务器.

  6. 目标服务器逐层解封装和分用。
    服务器收到数据以后,从下往上处理:以太网帧 → IP 数据报 → TCP/UDP 数据 → 应用数据

    数据链路层确认目标 MAC,网络层确认目标IP,传输层再根据端口号把数据交给对应的应用程序,比如 Web 服务.

这里最需要掌握的核心区别是:IP 地址负责端到端寻址,MAC 地址负责每一跳的链路传输。

比如一封快递从北京寄到上海:

  • IP 地址像最终的收件人地址,告诉整个运输系统“最终送到哪里”;
  • MAC 地址更像当前运输阶段的“下一站是谁”,每经过一个中转站都会变化;
  • 路由器就像中转中心,根据最终地址决定下一站往哪里走.

所以跨网络通信可以简单记成:判断不在同网段 → 发给默认网关 → 路由器根据目的 IP 逐跳转发 → 每一跳重新封装链路层帧 → 到达目标网络 → 最终交给目标主机。

再浓缩成一句话就是:跨网络传输中,路由器看 IP 决定“下一步往哪里走”,每一跳用 MAC 完成“这一段具体交给谁”。


①⽹络中的地址管理—认识IP地址





IP 地址是网络层使用的逻辑地址,用来标识网络中的主机或网络接口.它最重要的作用,就是帮助数据在不同网络之间找到最终的目标.

目前常见的IP协议有 IPv4 和 IPv6.我们平时学习和使用较多的是IPv4.IPv4 地址长度是 32 bit,也就是4字节,通常采用点分十进制表示,例如:

192.168.1.10

它由 4 个数字组成,每个数字对应 1 个字节,取值范围是 0~255.

IP地址为什么重要?
如果两台计算机只在同一个局域网中通信,可以主要依靠MAC地址完成帧的转发.但实际网络中,两台主机往往不在同一个局域网,中间可能隔着很多路由器.

这时候就需要 IP 地址.

可以把 IP 地址理解成一个最终目的地址.路由器收到数据之后,会查看数据包中的目的 IP 地址,再查询自己的路由表,决定下一步应该往哪个方向转发.

因此:MAC 地址主要解决“这一跳交给谁”,IP 地址主要解决“最终要到哪里”。

同网段和跨网段有什么区别?
假设主机 A 的地址是:

192.168.1.10/24

如果目标是:

192.168.1.20

两台主机属于同一个网段 192.168.1.0/24,主机 A 就可以先通过 ARP 获取主机 B 的 MAC 地址,然后通过交换机直接发送给 B.

也就是:同网段:直接找目标主机的 MAC。

但是,如果目标主机的 IP 是:

172.16.0.20

它和主机 A 不在同一个网段,那么主机 A 就不能直接把以太网帧交给远程主机,而是需要先交给默认网关.

这时候主机 A 获取的是默认网关的 MAC 地址,而不是远程主机的 MAC 地址.

也就是: 跨网段:先找默认网关的 MAC。

路由器在里面做什么?
当默认网关收到数据以后,会取出里面的 IP 数据报,查看目的 IP 地址.

例如:目的 IP:172.16.0.20

路由器查询自己的路由表,确定下一跳,然后重新封装一个新的链路层数据帧,再发送出去.

如果中间还有其他路由器,就会重复这个过程:收到帧 → 取出 IP 数据报 → 查看目的 IP → 查路由表 → 重新封装 → 发给下一跳

直到数据到达目标网络.

IP 地址和 MAC 地址的区别
这里是理解 IP 地址最关键的地方.

IP 地址工作在网络层,主要负责跨网络寻址和路由.

MAC 地址工作在数据链路层,主要负责当前链路上的数据帧交付.

因此,在一次跨网络通信过程中:

  • 源 IP、目的 IP体现的是通信的两个端点;
  • 每经过一台路由器,源 MAC 和目的 MAC 通常都会改变;
  • 路由器主要根据目的 IP选择下一跳;
  • 交换机主要根据MAC 地址转发数据帧.

在不考虑 NAT 等地址转换的简化情况下,可以理解为:IP 地址端到端基本不变,MAC 地址逐跳变化。

举个例子
假设主机 A:

192.168.1.10

访问服务器:

203.0.113.100

整个过程可以简单理解成:

主机 A
→ 判断服务器不在本地网段
→ ARP 获取默认网关 MAC
→ 把数据交给默认网关
→ 路由器查看目的 IP
→ 根据路由表逐跳转发
→ 到达服务器所在网络
→ 最后一台路由器获取服务器 MAC
→ 把数据交给服务器

所以可以用一句话总结:IP 地址就是网络中的“逻辑目的地址”,它让路由器知道数据最终应该送到哪里。

再配合前面学过的 MAC 地址,可以记住这句话:IP 管终点,MAC 管下一跳;交换机看 MAC,路由器看 IP。


五、Socket编程预备

5.1理解源IP地址和⽬的IP地址


源 IP 地址和目的 IP 地址,可以理解为网络通信中数据包的“发件地址”和“收件地址”.

当一台主机要发送数据时,网络层会在数据前面加入一个 IP 首部.这个首部中有两个非常重要的信息:

  • 源 IP 地址:表示数据从哪台主机、哪个网络接口发出来.
  • 目的 IP 地址:表示数据最终要发送到哪台目标主机、哪个网络接口.

例如:
主机 A:192.168.1.10
服务器 B:93.184.216.34

主机A访问服务器B时,IP数据包中就会包含:
源 IP:192.168.1.10
目的 IP:93.184.216.34

数据在网络中可能要经过很多台路由器.每台路由器都会查看目的 IP 地址,然后根据自己的路由表决定下一步把数据转发到哪里.

所以可以理解为:源IP告诉网络“数据从哪里来”,目的IP告诉网络“数据最终要去哪里”.

数据到达主机就结束了吗?
并不是.
一台计算机中可能同时运行很多程序,比如:

  • 浏览器
  • QQ
  • 下载工具
  • 邮件程序
  • Web 服务

IP 地址只能帮助数据找到目标主机,但数据到达这台主机以后,还需要进一步确定:到底应该把数据交给哪个应用程序?

这时候就需要传输层中的端口号.

例如:
IP 地址负责找到这台计算机,
端口号负责找到这台计算机里的具体程序.

所以可以把它类比成寄快递:IP 地址像小区和楼栋地址,端口号像具体的房间号.

快递先根据地址送到正确的大楼,然后再根据房间号交给具体的人.

在跨网络传输中有什么特点?
假设主机 A 的数据要经过多个路由器才能到达服务器 B.

整个过程可以简单表示为:
主机 A
→ 路由器 1
→ 路由器 2
→ ……
→ 服务器 B

路由器主要根据目的 IP 地址进行路由选择.

在不考虑 NAT 等地址转换的简化情况下,整个过程中:源 IP 和目的 IP 通常保持不变。

但是链路层中的 MAC 地址会随着每一跳发生变化.

因此前面学过的内容可以串起来:IP 地址负责端到端通信,MAC地址负责逐跳通信.

还要注意一个细节
严格来说,IP地址通常是分配给网络接口的,而不是简单理解成“一台主机永久唯一的身份证”.一台计算机可以有多个网卡,因此也可能同时拥有多个IP地址.

一句话总结:源 IP 表示数据从哪里来,目的 IP 表示数据最终到哪里去;IP 负责找到目标主机,端口号再负责找到目标主机中的具体应用程序。

可以再记一个口诀:源 IP 看来源,目的IP找终点;IP找主机,端口找程序.


5.2认识端⼝号


端口号(Port) 是传输层中用来区分不同网络应用或服务的编号.简单来说,IP 地址负责找到一台主机,端口号负责在这台主机中找到对应的网络服务或应用程序.

一台计算机上往往会同时运行很多程序,比如浏览器、QQ、数据库、Web 服务、SSH 服务等.网络数据到达目标主机以后,操作系统还需要判断:这份数据到底应该交给哪个程序处理?

这就是端口号的作用.

1.端口号是什么?
TCP 和 UDP 的端口号都是 16 位整数,所以取值范围是:

0 ~ 65535

例如一些常见的端口:

  • HTTP:80
  • HTTPS:443
  • SSH:22
  • FTP:21
  • DNS:53
  • MySQL:3306

可以把一台计算机想象成一栋大楼:

IP 地址 = 大楼地址
端口号 = 房间号

知道 IP 地址只能找到这栋楼;还需要知道端口号,才能找到具体的“房间”,也就是相应的网络服务.

2.为什么只有 IP 地址还不够?
假设服务器的 IP 地址是:

93.184.216.34

这台服务器上可能同时运行 Web 服务、SSH 服务、数据库服务等.

如果只发送到:

93.184.216.34

操作系统只能知道数据到了这台服务器,却不知道应该交给哪个服务.

加上端口以后,就可以区分:

93.184.216.34:80 → Web 服务
93.184.216.34:22 → SSH 服务
93.184.216.34:3306 → MySQL 服务

所以可以记成:IP 找主机,端口找服务。

3.源端口和目的端口
网络通信中通常同时存在两个端口.

例如你的浏览器访问一个 Web 服务器:
客户端:192.168.1.10:52345
服务器:93.184.216.34:80

这里:

源端口 52345 通常由客户端操作系统临时分配,用来标识这一次通信的本地端点.

目的端口 80 表示数据要交给服务器上的 Web 服务.

服务器返回数据时,方向反过来:
源端口:80
目的端口:52345

这样客户端操作系统才能知道返回的数据应该交给之前发起请求的那个连接.

4.端口号工作在哪一层?
端口号属于 传输层,主要出现在 TCP 或 UDP 的首部中.

数据到达目标主机以后,大致会经历:
以太网帧
↓
根据 IP 地址确认目标主机
↓
根据 TCP/UDP 进行处理
↓
根据目的端口号找到对应的应用
↓
把数据交给应用程序

因此端口号实际上承担了一个重要作用:分用.

也就是:同一台主机收到很多网络数据时,根据端口号把数据分别交给不同的应用.

5.一个更准确的理解
入门时经常说:“端口号用来标识进程。”

这样理解基本可以,但从技术上说,更准确的是:端口号标识的是 TCP/UDP 的通信端点(Socket),操作系统再把这个通信端点关联到相应的进程.

所以端口号并不等同于进程 ID.

另外,“一个端口只能被一个进程占用”也是一种入门简化.实际系统中还要结合 TCP/UDP、绑定的本地 IP、Socket 选项等判断.例如 TCP 的 80 端口和 UDP 的 80 端口并不是同一个端口空间。

一句话总结IP 地址负责把数据送到正确的主机,端口号负责把数据交给主机中正确的网络应用或服务。

最好记的一句话就是:IP 找电脑,Port 找程序。


①端⼝号范围划分

端口号是 16 位整数,所以范围是:0 ~ 65535

通常可以分为三类:

范围名称主要用途
0~1023系统端口 / 知名端口常见标准服务使用
1024~49151用户端口 / 注册端口各类应用和服务使用
49152~65535动态端口 / 私有端口客户端临时通信时常用

1.0~1023:知名端口
这部分端口通常分配给一些常见的网络服务.
例如:

  • 20/21:FTP
  • 22:SSH
  • 25:SMTP
  • 53:DNS
  • 80:HTTP
  • 443:HTTPS

可以理解为这些端口比较像网络服务中的“固定窗口”.

2.1024~49151:注册端口
这部分端口通常由各种应用程序、数据库、中间件等服务使用.
例如:

  • 3306:MySQL
  • 5432:PostgreSQL
  • 8080:经常作为 Web 服务的备用端口

这些端口中有很多已经向 IANA 注册,但并不是说所有端口都一定被某个程序占用.

3.49152~65535:动态/私有端口
这部分端口通常用于客户端临时端口.
比如你打开浏览器访问一个 HTTPS 网站时:
客户端:192.168.1.10:52345
服务器:93.184.216.34:443

这里的:

  • 443 是服务器的固定服务端口;
  • 52345 就可能是操作系统临时分配给浏览器连接的动态端口.

通信结束以后,这个临时端口可以被释放,以后再分配给其他连接.

需要注意:实际操作系统选择临时端口的范围可能有所不同,不一定严格使用完整的 49152~65535.

一句话记忆:0~1023 给经典服务,1024~49151 给普通应用,49152~65535 常用于临时连接。

另外,TCP 和 UDP 各自拥有独立的 0~65535 端口空间,所以 TCP 80 和 UDP 80 technically 是两个不同的通信端点.


②理解 “端⼝号” 和 “进程ID”

可以把 端口号(Port) 和 进程ID(PID) 理解成两个完全不同层面的标识:端口号解决“网络数据应该交给哪个网络服务”,PID 解决“操作系统内部这是哪个进程”.

先看一个例子
假设一台服务器的 IP 是:192.168.1.100
它上面运行了一个 Nginx Web 服务:

  • Nginx 监听端口:80
  • Nginx 进程 PID:3256

当客户端访问:192.168.1.100:80
网络数据到达服务器后,操作系统会看到 TCP 报文中的目的端口80,找到监听这个端口的 Socket,然后把数据交给对应的 Nginx 进程.

也就是:

192.168.1.100:80
↓
TCP 80 端口
↓
Socket
↓
Nginx 进程
↓
PID = 3256

所以,网络通信本身并不会携带 PID=3256.PID 是服务器操作系统自己内部使用的编号.

端口号是什么?
端口号属于 TCP/UDP 传输层,范围是:0 ~ 65535
它主要用于区分一台主机上的不同网络服务.
例如:

  • 80 → HTTP
  • 443 → HTTPS
  • 22 → SSH
  • 3306 → MySQL

因此我们经常说:IP 地址找到主机,端口号找到网络服务。

不过严格来说,端口号对应的是 Socket 通信端点,Socket 再由操作系统关联到进程.

PID是什么?
PID,全称 Process ID(进程标识符),是操作系统给每个运行中进程分配的编号.
比如:

PID 1024 → nginx
PID 2088 → mysqld
PID 3560 → sshd

PID 主要用于操作系统内部的:

  • 进程管理
  • 调度
  • 查看进程
  • 终止进程
  • 进程间关系管理

例如 Linux 中:

ps

Windows 中可以通过任务管理器查看 PID.

PID 通常只在当前操作系统内部有意义.

两者最大的区别

对比端口号 Port进程 ID PID
属于哪里TCP/UDP 传输层操作系统进程管理
作用区分网络通信端点/服务标识运行中的进程
范围0~65535由操作系统决定
网络中是否使用是否
是否会随程序重启变化服务端口通常可保持不变通常会变化
一个进程能否有多个可以监听/使用多个端口一个进程只有一个 PID

例如 Nginx 每次启动都可以继续监听 80:

第一次:80 → nginx → PID 3256

重启之后:80 → nginx → PID 4871

可以看到:端口还是 80,但 PID 已经变了。

一个很重要的关系

不要简单理解成:一个端口 = 一个进程

更准确的关系是:端口属于 Socket,Socket 由进程持有。

所以一个进程完全可以同时使用很多端口.

比如一个程序可以同时监听:

80
443
8080

而在某些操作系统机制下,通过 SO_REUSEPORT 等方式,多个进程也可能共同监听同一个端口.

用生活中的例子理解

可以把一台服务器想象成一家公司:
IP 地址 = 公司地址
端口号 = 服务窗口编号
PID = 员工工号

客户寄东西时,只需要知道:公司地址 + 服务窗口

并不需要知道工作人员的内部工号.

同样,客户端访问服务器时通常只需要知道:IP + Port

例如:192.168.1.100:80

至于这个端口背后当前到底由 PID 3256 还是 PID 4871 的进程处理,是服务器操作系统内部管理的问题.

一句话总结:端口号是网络通信的编号,PID 是操作系统管理进程的编号。

最好记成:IP 找主机,Port 找服务,PID 找进程。


③理解源端⼝号和⽬的端⼝号

源端口号和目的端口号都属于传输层,用来标识通信两端的应用程序或通信端点.

假设你的电脑通过浏览器访问一个 Web 服务器:客户端:192.168.1.10:52345 服务器:93.184.216.34:80

这里:

  • 源端口号:52345
    表示数据是从客户端哪个通信端点发出来的.客户端通常会由操作系统临时分配一个端口.

  • 目的端口号:80
    表示数据到达服务器后,应该交给哪个服务处理.80 通常表示 HTTP Web 服务.

所以请求报文可以理解为:

源 IP:192.168.1.10
源端口:52345
目的 IP:93.184.216.34
目的端口:80

也就是:从 192.168.1.10 的 52345 端口,发送给 93.184.216.34 的 80 端口。

当服务器返回数据时,方向会反过来:

源 IP:93.184.216.34
源端口:80
目的 IP:192.168.1.10
目的端口:52345

这时候 80 变成了源端口,52345 变成了目的端口.

为什么需要两个端口?
因为一台计算机可以同时运行很多网络程序,也可以同时建立很多连接.

例如你的电脑同时打开多个网页:

浏览器连接1:52345 → 80
浏览器连接2:52346 → 80
浏览器连接3:52347 → 443

即使这些连接访问同一个服务器,也可以通过不同的源端口区分不同的通信连接.

所以可以这样记:
源端口:数据从哪个通信端点发出来。
目的端口:数据要交给对方哪个通信端点。

再结合 IP 地址:
源 IP + 源端口 = 发送端
目的 IP + 目的端口 = 接收端

例如一个 TCP 连接常用下面这组信息来区分:源 IP + 源端口 + 目的 IP + 目的端口

一句话总结:IP 地址负责找到通信双方的主机,端口号负责找到主机内部对应的网络应用;源端口表示从哪里发,目的端口表示要交给谁。


④理解socket

可以把 Socket(套接字) 理解成:应用程序和网络协议栈之间的“通信接口”或“网络通信端点”.

程序本身不会直接操作网卡、TCP、IP,而是通过 Socket 告诉操作系统:“我要建立网络连接”“我要发送数据”“我要接收数据”.

先和前面的 IP、端口、PID 串起来
假设浏览器访问服务器:

客户端:192.168.1.10:52345
服务器:93.184.216.34:443

可以理解为:

浏览器进程
   ↓
Socket
   ↓
TCP
   ↓
IP
   ↓
网卡
   ↓
网络

浏览器把数据写入 Socket,操作系统再通过 TCP/IP 协议栈把数据发送出去.

所以:进程通过 Socket 使用网络。

Socket 和端口是什么关系?
端口号并不等于 Socket.

比如服务器创建一个 Socket,并让它监听:

IP:192.168.1.100
Port:80

可以简单理解为:
Socket = 一个网络通信端点
IP + Port = 这个端点的重要地址信息

对于一个已经建立的 TCP 连接,通常可以用四元组描述:

源 IP + 源端口 + 目的 IP + 目的端口

例如:

192.168.1.10:52345
        ↓
93.184.216.34:443

这就描述了一条 TCP 通信关系.

Socket 和进程是什么关系?
Socket 是由操作系统内核管理的网络对象,应用程序通过一个文件描述符或句柄来操作它.

例如:

浏览器进程 PID=3001
        ↓
     Socket
        ↓
192.168.1.10:52345
        ↓
      网络

所以更准确地说:进程持有 Socket,Socket 负责网络通信。

一个进程可以拥有很多 Socket.

比如浏览器同时打开很多网站:

浏览器进程
 ├─ Socket 1 → 网站 A
 ├─ Socket 2 → 网站 B
 ├─ Socket 3 → 网站 C
 └─ Socket 4 → 网站 D

这也是为什么一个浏览器进程可以同时建立很多网络连接.

服务器中的 Socket
服务器端更容易看出 Socket 的作用.

比如一个 Web 服务器监听 80 端口:

socket()
   ↓
bind()
   ↓
listen()
   ↓
accept()

大概含义是:

  • socket():创建一个 Socket
  • bind():绑定 IP 和端口
  • listen():开始监听客户端连接
  • accept():接受客户端连接

例如服务器先有一个:监听 Socket

专门负责等待别人连接.

当客户端连接进来之后,系统通常会再创建一个:已连接 Socket

专门负责和这个客户端通信.

所以:

服务器监听 Socket
      ↓
   accept()
      ↓
客户端A Socket   客户端B Socket   客户端C Socket

这样服务器就可以同时服务多个客户端.

用生活中的例子理解
可以把网络服务器想象成一家公司:

IP 地址 = 公司地址
端口号 = 服务窗口编号
Socket = 真正用于办理业务的通信窗口/通道
进程 = 负责处理业务的工作人员或程序

客户端并不是直接和“端口号”通信,而是操作系统通过 Socket 建立实际的网络通信端点.

一句话总结:Socket 是操作系统提供给应用程序使用网络通信的一种抽象接口和通信端点。

把前面的概念连起来,可以记成:IP 找主机,Port 找服务,Socket 建立通信端点,进程通过 Socket 收发数据。


5.3传输层的典型代表


传输层位于应用层和网络层之间,它的主要作用是为不同主机上的应用程序提供端到端的通信服务.前面我们讲过,IP地址负责把数据送到正确的主机,而传输层进一步解决:数据到达主机以后,应该交给哪个应用程序,以及数据应该以什么方式进行传输.

传输层最典型的两个协议就是 TCP 和 UDP.

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、可靠传输的协议.通信之前通常需要先建立连接,传输过程中会通过确认、序号、重传等机制,尽量保证数据不丢失、不重复,并且按照正确的顺序到达.因此TCP比较适合网页访问、文件传输、邮件等对数据完整性要求较高的场景.

UDP(User Datagram Protocol,用户数据报协议)则是一种无连接的传输协议.发送数据之前不需要建立连接,也没有TCP那么完整的确认、重传和顺序控制机制,因此协议开销更小、处理更简单、延迟通常也更低.它常用于DNS、实时音视频、在线游戏等更重视实时性的场景.不过,“UDP 更快”不是绝对规律,实际性能还取决于具体网络和应用设计.

传输层还有一个非常重要的概念,就是端口号.一台计算机可能同时运行浏览器、QQ、数据库、Web 服务等很多程序,因此数据到达主机后,还需要通过端口号把数据交给正确的应用.

比如:
客户端 192.168.1.10:52345
访问服务器 93.184.216.34:80

这里IP地址负责找到两台主机,而 52345 和 80 这样的端口号,则负责区分具体的通信端点和网络服务.

从操作系统角度看,TCP/IP 协议栈的核心部分通常由操作系统内核实现.普通应用程序不能直接操作网络协议栈,而是通过操作系统提供的 Socket 接口和系统调用来使用 TCP 或 UDP.

可以简单理解成:应用程序 → Socket → TCP/UDP → IP → 网卡 → 网络

所以,应用程序想发送数据时,并不是自己实现 TCP、IP,而是调用操作系统提供的接口,由操作系统内核中的网络协议栈完成后续的数据封装和传输.

一句话总结:传输层通过 TCP 或 UDP 为应用程序提供端到端通信,并利用端口号区分不同的网络应用;TCP 强调可靠,UDP 强调简单和低开销。


①认识TCP协议


TCP 全称是 Transmission Control Protocol,传输控制协议.它工作在传输层,主要负责在两台主机的应用程序之间提供面向连接、可靠、有序的字节流传输.

简单来说:TCP 的目标,就是尽可能保证数据能够完整、按顺序、可靠地从发送方到达接收方。

TCP 的几个核心特点
首先,TCP 是面向连接的.在正式发送数据之前,通信双方需要先建立连接,这个过程最典型的就是三次握手.

大致过程是:

客户端发送 SYN
服务器返回 SYN + ACK
客户端再发送 ACK

三次握手完成后,双方确认彼此都具备发送和接收数据的能力,TCP 连接就建立起来了.

其次,TCP 提供可靠传输.网络本身并不能保证数据绝对不会丢失,因此TCP使用了一系列机制来提高可靠性,比如:

  • 序号:给数据编号
  • 确认应答 ACK:告诉对方哪些数据已经收到
  • 超时重传:长时间没收到确认,就重新发送
  • 校验和:检查数据是否损坏
  • 滑动窗口:提高连续发送效率
  • 流量控制:避免发送太快,把接收方“撑爆”
  • 拥塞控制:避免整个网络因为发送过快而发生拥堵

所以 TCP 并不是因为网络本身可靠,而是:TCP 在不可靠的 IP 网络之上,通过一系列机制实现尽可能可靠的数据传输。

TCP 为什么能保证顺序?
TCP 会给传输的数据编号.

假设发送:数据 1 → 数据 2 → 数据 3

即使网络传输过程中数据到达顺序变成:数据 2 → 数据 1 → 数据 3

TCP 也可以根据序号重新排列,最后再按照正确顺序交给应用程序.

所以 TCP 对上层应用提供的是一个有序的字节流.

TCP 首部中有什么?
TCP 首部中有很多重要字段,例如:

  • 源端口号
  • 目的端口号
  • 序号
  • 确认号
  • 标志位,如 SYN、ACK、FIN
  • 窗口大小
  • 校验和

这些字段共同支持连接管理、可靠传输、流量控制等功能.

TCP 如何断开连接?
TCP 通信完成以后,还需要释放连接,典型过程叫四次挥手.

可以简单理解为:

A:我没有数据要发了,FIN
B:收到,ACK
B:我也没有数据要发了,FIN
A:收到,ACK

之所以通常是四次,是因为 TCP 是全双工通信,两个方向可以分别关闭.

TCP 用在哪些地方?
TCP 适合那些更强调数据完整性和可靠性的场景,例如:

  • HTTP / HTTPS
  • FTP
  • SSH
  • SMTP
  • IMAP / POP3
  • 数据库连接等

这些应用通常不能接受数据随意丢失.

TCP 和 UDP 的简单区别
可以这样记:
TCP:先建立连接,再可靠地传。
UDP:直接发送,不负责确认和重传。

因此TCP的可靠性更高,但协议机制也更复杂;UDP 更简单、开销更小.

一句话总结:TCP 是一种面向连接、可靠、有序、面向字节流的传输层协议,它通过确认、重传、序号、流量控制和拥塞控制等机制,让数据尽可能可靠地从一端传到另一端。

记忆关键词可以直接记成:连接、确认、重传、有序、流控、拥塞控制。


②认识UDP协议


UDP 全称是 User Datagram Protocol,用户数据报协议.它和 TCP 一样工作在传输层,负责在不同主机的应用程序之间传输数据.

UDP 最大的特点可以概括为:无连接、面向数据报、协议简单、开销小,但不保证可靠传输。

1.UDP 是“无连接”的
TCP 在发送数据之前通常需要先建立连接,而UDP不需要.

应用程序有数据要发送时,可以直接把数据交给 UDP:应用程序 → UDP → IP → 网络

不需要像 TCP 那样进行三次握手.

所以 UDP 的通信过程比较简单,建立通信的额外开销也比较小.

2.UDP不保证数据一定到达
UDP 把数据发送出去以后,本身不会负责确认对方是否收到.

例如发送方连续发送:

数据报 1
数据报 2
数据报 3

网络中可能出现:

  • 数据报丢失
  • 到达顺序改变
  • 重复到达
  • 网络拥塞导致部分数据无法及时到达

UDP 本身通常不会像 TCP 那样进行确认、重传和重新排序.

因此可以把 UDP 类比成:寄普通明信片:我负责寄出去,但不保证一定收到,也不会自动补寄。

如果应用确实需要可靠性,可以在 UDP 上层自己实现确认、重传等机制.

3.UDP 是“面向数据报”的
TCP 面向的是字节流,而 UDP 面向的是一个个独立的数据报(Datagram).

例如应用程序调用 UDP:

第一次发送:“你好”
第二次发送:“今天上课吗?”

UDP 会把它们作为两个独立的数据报发送.

因此 UDP 会保留应用发送数据的消息边界.

可以简单理解为:应用发一个包,UDP 就处理一个包.

4.UDP 首部非常简单
UDP 的首部只有 8 字节,只有四个主要字段:

  • 源端口号:数据从哪个应用通信端点发出
  • 目的端口号:数据要交给对方哪个应用通信端点
  • 长度:UDP 首部加数据的总长度
  • 校验和:检查数据在传输过程中是否发生错误

所以 UDP 相比 TCP 要简单很多.

可以记成:源端口 + 目的端口 + 长度 + 校验和 = 8 字节

5.为什么还要用 UDP?

有人可能会问:TCP 更可靠,为什么不全部使用 TCP?

因为有些应用更加关注实时性和较小的协议开销.

例如实时语音通话中,如果某一小段声音丢失了,通常没有必要等待它重新传输,因为等它重新传回来时,这段声音已经“过时”了.

因此很多实时应用更愿意:允许少量数据丢失,也不愿意因为重传造成较大延迟。

UDP 常见于:

  • DNS 域名解析
  • DHCP
  • NTP 时间同步
  • SNMP
  • 实时音视频
  • 在线游戏
  • 一些流媒体协议

需要注意,DNS 并不只使用 UDP,某些情况下也会使用 TCP.

6.UDP 和 TCP 的核心区别
可以简单理解:

TCPUDP
面向连接无连接
可靠传输不保证可靠
保证顺序不保证顺序
有确认、重传本身没有确认、重传
面向字节流面向数据报
首部较复杂首部只有 8 字节
适合可靠性要求高的场景适合实时性或轻量通信场景

不过要注意:UDP 并不等于一定比 TCP 快。

UDP 只是协议机制更简单、额外开销更少,最终实际速度和延迟还取决于网络环境以及应用程序自己的设计.

一句话总结:UDP 是一种无连接、面向数据报、轻量级的传输层协议,它负责把数据尽快发送出去,但不负责保证数据一定到达、按序到达或自动重传。

可以记一个口诀:
TCP:先连接,求可靠。
UDP:直接发,重效率。


5.4⽹络字节序


网络字节序(Network Byte Order),解决的是这样一个问题:不同计算机可能采用不同的字节存储顺序,但网络通信必须使用统一的顺序.

计算机在保存一个多字节整数时,常见有两种方式:大端字节序(Big-endian)和小端字节序(Little-endian).

比如一个 16 位整数:0x1234

它实际上由两个字节组成:0x12 和 0x34

如果从低地址开始存储:

  • 大端:0x12 0x34
  • 小端:0x34 0x12

也就是说:
大端:高位字节放在前面。
小端:低位字节放在前面。

为什么网络中必须统一?
假设主机 A 是小端机器,而主机 B 是大端机器.

如果 A 直接把内存中的多字节整数原样发送出去,B 又按照自己的方式解释,那么双方可能会得到不同的数值.

例如发送:0x12345678

大端顺序是:12 34 56 78

小端内存中可能是:78 56 34 12

如果通信双方没有统一规则,就可能把同一组字节理解成完全不同的数字.

因此 TCP/IP 规定:网络字节序采用大端字节序。

也就是:高位字节先发送,低位字节后发送。

这样无论发送方是大端主机还是小端主机,只要发送时统一转换成网络字节序,接收时再转换成本机字节序,双方就能正确理解数据.

发送和接收时怎么处理?
如果发送主机本身是小端机器:

主机字节序
↓ 转换
网络字节序(大端)
↓ 网络传输

接收端收到后:

网络字节序(大端)
↓ 转换
接收主机自己的字节序

所以可以理解成:发送前统一,接收后还原.

C语言中常见的转换函数
网络编程中经常会看到:

htonl()
htons()
ntohl()
ntohs()

名字可以这样记:

  • h:host,主机
  • n:network,网络
  • l:32 位整数(历史命名 long)
  • s:16 位整数(short)

所以:

htonl():主机字节序 → 网络字节序,32 位
htons():主机字节序 → 网络字节序,16 位
ntohl():网络字节序 → 主机字节序,32 位
ntohs():网络字节序 → 主机字节序,16 位

例如 TCP/UDP 中的端口号是 16 位整数,因此在底层 Socket 编程中经常会看到:

addr.sin_port = htons(8080);

意思就是先把 8080 转换成网络要求的大端格式.

一个容易误解的地方
网络字节序主要针对多字节数值字段,比如端口号、长度、序号等.

并不是说字符串 "hello" 或一段文件内容也要整体倒序.

例如:H e l l o

仍然按照原来的字节顺序发送.

所以网络字节序关注的是:一个多字节整数内部,各个字节按照什么顺序排列。

它也不是“位顺序”,不要把 bit(位) 和 byte(字节) 混在一起.

一句话总结:网络字节序就是 TCP/IP 为多字节整数规定的统一字节排列方式,采用大端字节序,即高位字节在前、低位字节在后.

可以记一个口诀:主机端序可以不同,网络端序统一大端;发送前转网络序,接收后转主机序.


5.5Socket通用结构体

①Socket常⻅API

Socket常见API 理解为:应用程序通过这些函数向操作系统申请和使用网络通信能力.

在Linux / Unix网络编程中,最核心的一组 Socket API 是:socket → bind → listen → accept / connect → send / recv → close

其中,服务器端和客户端的调用流程不同.

1.socket():创建 Socket

int fd = socket(AF_INET, SOCK_STREAM, 0);

作用是向操作系统申请一个 Socket.

常见参数:

  • AF_INET:IPv4
  • AF_INET6:IPv6
  • SOCK_STREAM:TCP
  • SOCK_DGRAM:UDP

返回值 fd 是一个文件描述符.之后程序就是通过这个 fd 操作 Socket.

可以理解为:socket() = 创建一个网络通信端点。

2.bind():绑定 IP 和端口

bind(fd, ...);

主要用于服务器.

服务器创建 Socket 后,需要告诉操作系统:“我希望监听本机的哪个 IP、哪个端口。”

例如:

0.0.0.0:8080

表示监听本机所有网络接口的 8080 端口.

所以:bind() = 给 Socket 绑定本地 IP 和端口.

客户端通常不需要显式调用 bind(),操作系统可以自动分配本地 IP 和临时端口.

3.listen():进入监听状态

listen(fd, backlog);

主要用于 TCP 服务器.

执行后表示:“这个 Socket 开始等待客户端建立 TCP 连接。”

例如:

listen(fd, 128);

这里的 128 与等待处理的连接队列有关.

所以:listen() = 把 TCP Socket 变成监听 Socket。

4.accept():接收客户端连接

int client_fd = accept(fd, ...);

服务器调用 accept() 等待客户端连接.

这里很重要:accept() 会返回一个新的 Socket。

原来的 fd 继续负责监听新的客户端,而新的 client_fd 专门负责与当前客户端通信.

可以理解为:

监听 Socket
    │
    ├── accept → 客户端A Socket
    ├── accept → 客户端B Socket
    └── accept → 客户端C Socket

所以:accept() = 从监听 Socket 中取出一个已经建立好的 TCP 连接.

5.connect():主动连接服务器
客户端通常调用:

connect(fd, ...);

例如连接:

192.168.1.100:8080

对于 TCP 来说,调用 connect() 会触发 TCP 建立连接的过程,也就是前面学过的三次握手.

因此:connect() = 客户端主动向服务器发起连接.

TCP 客户端与服务器流程
可以直接记住:

TCP服务器                    TCP客户端

socket()                     socket()
   ↓                            ↓
bind()                       connect()
   ↓                            ↓
listen()                     send()/recv()
   ↓                            ↓
accept()                     close()
   ↓
send()/recv()
   ↓
close()

服务器端:socket → bind → listen → accept → recv/send → close

客户端:socket → connect → send/recv → close

6.send():发送数据

send(fd, buf, len, 0);

将应用程序中的数据交给 Socket,再由操作系统的 TCP/IP 协议栈处理.

大致过程:

应用程序
   ↓ send()
Socket
   ↓
TCP
   ↓
IP
   ↓
网卡

②Struct sockaddr和sockaddr_in结构

//struct sockaddr
struct sockaddr
{
    __SOCKADDR_COMMON (sa_);    /* Common data: address family and length. */
    char sa_data[14];           /* Address data. */
};

//struct sockaddr_in
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number. */
    struct in_addr sin_addr;    /* Internet address. */

    /* Pad to size of `struct sockaddr'. */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                           __SOCKADDR_COMMON_SIZE -
                           sizeof (in_port_t) -
                           sizeof (struct in_addr)];
};

①socket API是⼀层抽象的⽹络编程接⼝,适⽤于各种底层⽹络协议,如IPv4、IPv6,以及后⾯要讲的UNIXDomain Socket. 然⽽, 各种⽹络协议地址格式并不相同.
②IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址⽤sockaddr_in结构体表⽰,包括16位地址类型,16位端⼝号和32位IP地址.
③IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的⾸地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
④socket API可以都⽤struct sockaddr *类型表示,在使⽤的时候需要强制转化成sockaddr_in;这样的好处是程序的通⽤性,可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数.
⑤虽然socket api的接⼝是sockaddr, 但是我们真正在基于IPv4编程时,使⽤的数据结构是sockaddr_in;这个结构⾥主要有三部分信息: 地址类型, 端⼝号, IP地址.


③in_addr结构

/* Internet address. */
typedef uint32_t in_addr_t;

struct in_addr
{
    in_addr_t s_addr;
};


🚀真正的勇者不是流泪的人,而是含泪奔跑的人!

敬请期待下一篇文章内容


每日心灵鸡汤: 普通人买情绪,中产买路径、高净值买判断!

一个人说什么话,往往已经暴露了他所处的位置.当一个人不断跟我诉苦,说自己不容易、家庭拖累、环境不好,他大概率还是普通人,因为他最缺的是支撑、希望和重新行动起来的力量;当一个人问我接下来该怎么做、该学什么、该走什么路径,他大概率已经进入中产阶段,因为他真正缺的是一条更清晰、更有效率的上升路径;而当一个人告诉我自己已经有几个不错的选择,却不知道该选哪一个,他往往已经是高净值人群,因为他不缺机会,也不缺资源,真正缺的是判断.所以,普通人买情绪,中产买路径,高净值买判断.

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2401_87629362/article/details/166991638

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--