前面我们暂时结束了关于Linux的系统部分的内容学习,接下来我们将学习Linux中最重要的部分------网络。而这也就是现代IT行业中涉及到的最广泛的领域。
目录
[1. 解决了"互联互通"的问题(打破厂商锁定)](#1. 解决了“互联互通”的问题(打破厂商锁定))
[2. 解决了"网络健壮性"的问题(核战阴影下的设计)](#2. 解决了“网络健壮性”的问题(核战阴影下的设计))
[3. 解决了"网络资源复用"的问题(从独占到共享)](#3. 解决了“网络资源复用”的问题(从独占到共享))
[1. 本质区别](#1. 本质区别)
[2. 映射关系:N对N](#2. 映射关系:N对N)
[3. 操作系统如何关联?](#3. 操作系统如何关联?)
[1. htonl() ------ 32位主机字节序转网络字节序](#1. htonl() —— 32位主机字节序转网络字节序)
[2. htons() ------ 16位主机字节序转网络字节序](#2. htons() —— 16位主机字节序转网络字节序)
[3. ntohl() ------ 32位网络字节序转主机字节序](#3. ntohl() —— 32位网络字节序转主机字节序)
[4. ntohs() ------ 16位网络字节序转主机字节序](#4. ntohs() —— 16位网络字节序转主机字节序)
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[发送数据:send() / write() / sendto()](#发送数据:send() / write() / sendto())
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[接收数据:recv() / read() / recvfrom()](#接收数据:recv() / read() / recvfrom())
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
[关闭连接:close() 与 shutdown()](#关闭连接:close() 与 shutdown())
[1. 作用](#1. 作用)
[2. 表达式](#2. 表达式)
[3. 参数选项](#3. 参数选项)
[4. 返回值](#4. 返回值)
网络发展的历史
1. 冷战萌芽与理论奠基(20世纪50-60年代)
这个时期的驱动力并非商业,而是军事和科研。
-
背景: 当时主流的通信方式是电路交换(如电话线),一旦线路被切断,通信就中断了。美国军方需要一个没有中心、部分损毁仍能工作的通信系统。
-
关键概念诞生: 保罗·巴兰等人提出了分组交换的概念。它把数据切成一个个小块(包),每个包独立寻找路径到达目的地。这彻底改变了通信的基础逻辑。
-
标志性事件: 1969年,ARPANET(阿帕网) 诞生,连接了加州大学洛杉矶分校等四个节点。它被公认为现代互联网的鼻祖。
2. 协议统一与网络互联(20世纪70-80年代初)
这段时间是"诸侯割据"到"书同文、车同轨"的关键时期。当时出现了许多网络技术,但它们互不兼容。
-
TCP/IP的诞生: 为了解决网络互联的问题,罗伯特·卡恩和温顿·瑟夫设计了TCP/IP协议族。它的核心思想是:"只要大家都遵守这个协议,不管底下是什么网络(以太网、令牌环网等),都能互联起来。"
-
决定性时刻: 1983年1月1日,ARPANET正式从NCP协议切换到TCP/IP。这一天通常被视为现代互联网的诞生日。
3. 网络普及与商业化浪潮(20世纪80年代末-90年代)
这是网络走出象牙塔,进入千家万户和普通企业的时代。
-
以太网的胜利: 在局域网领域,以太网凭借简单、便宜、不断提速(从10M到100M到1G)的优势,击败了Token Ring(令牌环网)等竞争者,成为事实标准,一直延续到今天。
-
万维网(WWW)的发明: 1989年,蒂姆·伯纳斯-李发明了万维网,提出了HTTP协议和HTML语言,并创造了第一个网页浏览器。它让互联网从一个只有极客才能使用的"命令行"变成了普通人也能浏览的"图形化世界"。
-
浏览器之争与爆发: 90年代中期,网景浏览器的上市开启了互联网的第一次大繁荣。
4. 移动互联与云计算(21世纪初-2010年代)
互联网接入从"有线"变成了"无线",计算能力从"终端"搬到了"云端"。
-
无线接入普及: Wi-Fi(802.11标准)和后来3G/4G(LTE)技术的成熟,让人们摆脱了网线的束缚。
-
数据中心崛起: 随着谷歌、亚马逊等公司的壮大,网络架构开始围绕大规模数据中心设计。传统的"接入-汇聚-核心"三层架构逐渐向Spine-Leaf(脊叶) 等扁平化、高带宽、低延迟的架构演进,以适应东西向流量的爆发。
-
万物互联的雏形: 网络不再只是连接电脑,而是开始连接手机、传感器等各种设备。
5. 智能与内生安全(现在进行时)
这是我们现在所处的时代,网络正在变得更快、更智能、更复杂。
-
全光与确定性: 光传输正在不断逼近香农极限,同时网络开始具备"确定性"能力,能为工业控制、自动驾驶提供微秒级的低延迟保证。
-
云原生与SDN(软件定义网络): 网络正在全面软件化。通过SDN解耦硬件和软件,通过NFV(网络功能虚拟化)将网络功能虚拟化运行在通用硬件上,网络变得像水和电一样,可以按需调度。
-
AI与安全: 一方面AI在辅助管理复杂的网络,另一方面网络安全已从过去的"防病毒"演变为内生安全、零信任架构。
协议
概念
协议就是一组规则和约定 ,它规定了通信双方**"如何发起通信"、"用什么格式说话"、"如何回应"、"遇到错误怎么办"** 以及**"如何结束通信"** 。是通信双方都认识的数据类型。
举个例子,两个人见面握手:
-
一个人伸出手(发起连接)。
-
另一个人也伸出手握住(确认响应)。
-
这就是一个最简单的人际交互协议。
在网络里,从你点亮电脑到打开百度,背后有成百上千个这样的"握手"协议在默默运行。
协议的三要素
一个完整的网络协议,通常包含三个核心要素,缺一不可:
-
语法: 定义了数据的格式 。就像写信,第一行写邮编,第二行写地址,最后是正文。语法规定了这一段二进制数据里,哪几位是源地址,哪几位是目标地址,哪几位是数据内容。它解决的是"怎么说"的问题。
-
语义: 定义了每一段信息的含义 和控制信息。比如,收到一个值为
SYN的标识,意思是"我要请求建立连接";收到ACK的意思是"我确认收到了"。它解决的是"说什么"以及"对方该怎么做"的问题。 -
时序: 定义了事件发生的顺序 。必须先说完"你好",才能说"吃了没"。在网络里,必须是先建立连接(三次握手),然后才能发送HTTP请求,最后才是断开连接。它解决的是"什么时候说"的问题。
制定协议相关的组织
1. IETF ------ 互联网工程的"总工头"
这是最核心、最活跃 的协议制定机构。我们天天挂在嘴边的TCP/IP、HTTP、DNS、FTP、SMTP,全是它的功劳。
-
它怎么工作? 任何人(是的,包括你)都可以写一份技术文档,提交给IETF讨论。如果被采纳,就会发布为RFC(Request for Comments,征求意见稿)。RFC就是互联网协议的正式文本。
-
有趣的是: 这个名字"Request for Comments"(征求意见)保留了早期的开放风格------任何人都可以评论。但它现在实际上是正式标准。
-
特点: 它是开放、透明的,靠技术实力说话,不是靠钱或权力。
2. IEEE ------ 电气与电子工程师协会
如果说IETF定的是软件层面的"交通规则",那IEEE定的大多是硬件层面的"造路标准"。
-
代表作: 你每天都在用的 Wi-Fi ,它的标准是 IEEE 802.11 ;还有以太网 的标准 IEEE 802.3。
-
地位: 它是一个庞大的专业协会,不仅管网络,还管电气、电子、航空航天等。在网络硬件领域,它是绝对的权威。
3. W3C ------ 万维网联盟
由万维网发明者蒂姆·伯纳斯-李爵士创立,专门负责Web技术的标准化。
-
代表作: HTML、CSS、XML 这些你打开网页就能看到的东西,都是W3C定的。
-
补充: HTTP以前是W3C和IETF一起管的,现在HTTP的重任主要在IETF。
4. ISO ------ 国际标准化组织
这是一个全球性的国家标准机构联盟,非常庞大。
-
代表作: 著名的OSI七层模型 就是它提出的(虽然这个模型没在实际中打败TCP/IP,但它作为教学框架影响深远)。另外,像OSPF路由协议,也是ISO标准化的。
-
特点: 它的流程通常比IETF更正式、更缓慢一些。
协议分层
协议分层,就是把网络通信这个复杂的任务,按照功能的不同,切割成若干个相互独立、又相互关联的层级。每个层级只负责通信过程中的某一个特定环节。上层依赖下层提供的服务,下层为上层提供支持,但上下层之间互不干扰。
最著名的分层模型有两个:
-
OSI七层模型(理论标准):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
-
TCP/IP四层模型(事实标准):网络接口层、网络层、传输层、应用层。
为什么需要协议分层?
因为早年间,工程师们要解决的问题过于复杂繁多:
-
如何把0和1变成电信号?
-
如何保证信号在铜线上不丢失?
-
如何找到千里之外的服务器?
-
如果数据丢了怎么办?
-
如何让不同厂家(IBM、DEC、苹果)的设备互相通信?
这些内容跨度大,内容杂,如果全放到一个软件内显然程序会大得难以维护。而分层就是为了应对这种复杂性而诞生的。
协议分层的好处
1. 独立性与解耦(各扫门前雪)
这是最大的好处。
-
底层技术变了,不影响上层: 20年前我们用铜线上网,现在用光纤,甚至用5G上网。对于上层的浏览器和Web服务器来说,它完全感知不到。只要IP层(网络层)的接口不变,底层的介质随便换。
-
应用变了,不影响下层: 20年前主要是发邮件、浏览网页,现在是刷短视频、玩VR游戏。应用的流量爆炸式增长,但只要应用层调用传输层的接口(Socket)不变,下层的路由器和交换机依然照常工作。
2. 促进标准化与 interoperability(互联互通)
因为分层,才有了明确的接口标准。
-
华为的路由器(网络层)可以和思科的交换机(链路层)无缝对接,只要他们都遵守IEEE和IETF的标准。
-
微软的浏览器(应用层)可以访问苹果服务器上的网页(应用层),只要他们都遵守HTTP协议。
-
没有分层带来的清晰边界,这种跨厂商、跨系统的互联互通是无法想象的。
3. 便于维护与排错
这是工程师最实用的好处。当网络出问题时,分层思想指导我们沿着层去排查。
-
物理层(第1层): 看看网线是不是松了,光纤是不是断了。
-
链路层(第2层): 看看MAC地址对不对,交换机配置有没有问题。
-
网络层(第3层): 看看IP地址通不通,路由表对不对。
-
传输层(第4层): 看看端口能不能通,防火墙有没有拦截。
如果不懂分层,你会觉得整个网络就是一个黑盒,无从下手。有了分层,你就能把问题限定在某一层,快速定位故障。
4. 促进技术进步与并行开发
-
并行开发: 当年设计TCP/IP的时候,一群人可以同时设计应用层协议(如HTTP),另一群人设计网络层协议(如IP),只要约定好接口,就能同时推进。
-
技术演进: 我们可以把Wi-Fi从802.11n升级到802.11ac(物理/链路层),完全不影响你电脑上的微信(应用层)。这种"热插拔"式的技术升级,全靠分层隔离了变化。
5. 封装与复用
分层强制了封装。每一层把本层的核心逻辑封装在内部,只通过标准接口对外提供服务。
这意味着底层的服务可以被上层无数次复用。比如TCP/IP提供的可靠传输服务,可以被HTTP、FTP、SMTP等无数个应用层协议反复使用,而不需要每个应用自己去实现一遍拥塞控制和重传机制。
OSI七层模型
| 层号 | 层名称 | 核心功能描述 | 常见协议/技术/设备举例 |
|---|---|---|---|
| 7 | 应用层 | 直接面向用户应用,提供网络服务接口。 | HTTP、HTTPS、FTP、SMTP、DNS、Telnet |
| 6 | 表示层 | 负责数据格式转换、加密解密、压缩解压。 | SSL/TLS(加密)、JPEG/ASCII(格式转换) |
| 5 | 会话层 | 管理会话的建立、维持和终止,控制对话同步。 | NetBIOS、RPC(远程过程调用)、SQL会话 |
| 4 | 传输层 | 提供端到端的可靠或不可靠传输,负责分段、重组、流量控制和差错控制。 | TCP (传输控制协议)、UDP(用户数据报协议)、端口号 |
| 3 | 网络层 | 负责逻辑寻址(IP地址)和路由选择,将数据包从源端转发到目的端。 | IP协议 (IPv4/IPv6)、路由协议 (OSPF、BGP、RIP)、路由器 |
| 2 | 数据链路层 | 负责将网络层的数据包封装成帧,进行物理寻址(MAC地址),检测并纠正物理层传输中的错误。 | 以太网协议 、Wi-Fi(802.11) 、PPP 、交换机 、网卡 |
| 1 | 物理层 | 负责在物理介质上传输原始比特流,定义电压、线缆接口、数据速率等机械、电气和过程特性。 | 双绞线、光纤、同轴电缆、中继器、集线器、RJ-45接口 |
TCP/IP四(五)层模型
四层模型
| 层号 | 层名称 | 核心功能描述 | 常见协议/技术/设备举例 |
|---|---|---|---|
| 4 | 应用层 | 对应OSI的上三层(应用层、表示层、会话层),负责为用户提供网络应用服务,包括数据格式转换和会话管理。 | HTTP、HTTPS、FTP、SMTP、DNS、SSH 、DHCP |
| 3 | 传输层 | 功能与OSI传输层相同,负责端到端通信,提供可靠或不可靠的数据传输服务。 | TCP 、UDP、端口号 |
| 2 | 网络层 | 也称为网际互联层,核心功能是IP寻址、路由选择和数据包转发,实现跨网络的通信。 | IP协议 (IPv4/IPv6)、ICMP (ping命令)、ARP (地址解析协议,实际工作在层2和层3之间)、路由器 |
| 1 | 网络接口层 | 也称链路层 或主机-网络层,对应OSI的数据链路层和物理层,负责从主机到网络的物理连接和数据帧传输。 | 以太网、Wi-Fi、PPP、光纤、交换机、网卡、集线器 |
五层模型
| 层号 | 层名称 | 核心功能描述 | 常见协议/技术/设备举例 |
|---|---|---|---|
| 5 | 应用层 | 直接面向用户应用,提供网络服务接口,包含数据格式、加密、会话管理等(合并了OSI的上三层)。 | HTTP、HTTPS、FTP、SMTP、DNS、SSH、DHCP |
| 4 | 传输层 | 负责端到端的通信,提供可靠(TCP)或不可靠(UDP)的数据传输服务,进行端口寻址和流量控制。 | TCP 、UDP、端口号 |
| 3 | 网络层 | 负责逻辑寻址(IP地址)和路由选择,将数据包从源端跨网络转发到目的端。 | IP协议 (IPv4/IPv6)、ICMP 、路由协议 (OSPF、BGP)、路由器 |
| 2 | 数据链路层 | 负责将网络层的数据包封装成帧,进行物理寻址(MAC地址),实现同一局域网内的设备间数据传输,并检测错误。 | 以太网协议 、Wi-Fi(802.11) 、PPP 、交换机 、网卡 |
| 1 | 物理层 | 负责在物理介质上传输原始比特流,定义电压、线缆接口、数据速率等机械、电气特性。 | 双绞线、光纤、同轴电缆、中继器、集线器、RJ-45接口 |
TCP/IP协议
概念
TCP/IP不是一个孤立的协议,它是一个庞大的协议家族。从不同角度看,它有不同的含义:
1. 从协议构成角度:它是传输控制协议和网际协议的合称
-
TCP :负责管数据传得**"稳不稳"**。它就像一个负责的快递员,会把数据拆分成一个个包裹,编号,送到对方后要求对方签收确认,如果发现包裹丢了,会自动重发,保证数据完整无损地到达。
-
IP :负责管数据发得**"对不对"**。它就像一个只认地址的快递分拣员,只在每个包裹上写上源地址和目标地址(IP地址),然后根据路由表决定下一站往哪儿扔,但它不关心包裹有没有丢,丢了也不重发。
2. 从体系结构角度:它是一套分层的通信模型
就是我们之前聊过的TCP/IP四层或五层模型。它规定了通信这件事要分几步走:应用层(你),传输层(可靠保障),网络层(寻址路由),链路层(物理传输)。每一层各司其职,各层之间通过标准的接口协作。
3. 从行业标准角度:它是互联网的"世界语"
TCP/IP是一套开放的、免费的、任何人都可以基于它开发产品的标准(以RFC文档形式存在)。正是因为它是开放的,不同厂商的设备(比如思科的路由器、华为的交换机、你的Windows电脑、我的苹果手机)才能无障碍地沟通。这是互联网之所以成为互联网的基石。
为什么需要TCP/IP协议?
在TCP/IP成为事实标准之前,网络世界是混乱的。为什么它被需要?因为它解决了当时最棘手的几个问题:
1. 解决了"互联互通"的问题(打破厂商锁定)
-
背景:在TCP/IP之前,各大厂商(如IBM、DEC、Novell)都有自己的网络协议(如SNA、DECnet、IPX/SPX)。它们像一个个封闭的王国,买了IBM的设备,就只能用IBM的协议和另一台IBM的设备通信。如果你想混合使用不同厂商的设备,或者想把两个不同的网络连起来,几乎不可能,或者成本极高。
-
TCP/IP的答案 :它定义了一个中立的、厂商无关的标准。只要你的设备支持TCP/IP(现在几乎所有的设备都支持),不管你是哪个牌子,就能接入同一个网络。它打破了技术壁垒,促成了全球大联网。
2. 解决了"网络健壮性"的问题(核战阴影下的设计)
-
背景:TCP/IP的早期研究(ARPANET时期)有军事背景。军方需要一个能在核打击下仍然能工作的通信网络。传统的电话网络是"中心化"的,炸掉中心枢纽,全网瘫痪。
-
TCP/IP的答案 :它采用了分组交换 和无连接的设计。数据被切成包,每个包独立寻找路径。网络中没有中央控制中心,即使一部分节点被摧毁,数据包也能绕过损坏区域,从其他路径到达目的地。IP协议的这种"尽力而为"加上路由协议的动态调整,赋予了互联网极高的生存能力。
3. 解决了"网络资源复用"的问题(从独占到共享)
-
背景:早期的通信方式是电路交换(打电话)。当你打通一个电话,即使双方都不说话,这条线路也被你独占,别人不能用,造成了极大的资源浪费。
-
TCP/IP的答案 :分组交换让网络资源变成了统计复用。数据只在有东西要发送时才占用线路。就像高速公路,大家共用,而不是每个人都有专属的私人车道。这极大地提高了网络传输效率,让有限的带宽可以服务更多的用户。
TCP/IP协议与OS的关系
协议和OS全是C和汇编写的。

网络传输的基本流程
局域网网络传输的通信流程(以以太网为例)
局域网通信原理
以太网通信需要三个核心要素:MAC地址 、ARP协议 和交换机的工作机制
以太网通信的本质,是基于MAC地址寻址 和交换机转发 的局域网数据链路层通信过程。其核心机制可归纳为:地址解析协议(ARP)建立IP与MAC的映射关系,透明桥接(交换)实现基于MAC地址表的数据帧精确转发。
MAC地址
MAC地址是固化 在网络接口控制器(NIC,即网卡)出厂时的硬件地址,用于在同一广播域(即局域网段)内唯一标识一个网络接口 。它工作在OSI模型的第二层(数据链路层),是设备在物理介质上收发数据帧的直接依据。
MAC地址通常由48位二进制数表示,表现为12个十六进制字符,如 00:1A:2B:3C:4D:5E。其结构包含两个关键部分:
1. 结构分解
-
前24位(6个十六进制数) :组织唯一标识符(OUI) ,由IEEE分配,标识网卡制造商。例如,
00:1A:2B可能属于某特定厂商。 -
后24位 :网络接口控制器特定值,由厂商自行分配,确保同一OUI下的每个网卡地址唯一。
2. 地址位特殊含义
-
第1字节的最低有效位(第1位):标识地址类型。
-
0:单播地址(unicast),表示帧发往单个目标。
-
1:组播地址(multicast),表示帧发往一组设备。
-
-
第1字节的次低位(第2位):标识地址管理范围。
-
0:全局唯一地址(全球唯一,由IEEE分配)。
-
1:本地管理地址(locally administered),可由管理员或虚拟化软件自定义,常用于虚拟机、集群等场景。
-
3. 特殊MAC地址
-
广播地址 :
FF:FF:FF:FF:FF:FF,所有位为1,表示帧应被所有网卡接收。 -
组播地址 :以
01:00:5E(IPv4组播)等特定OUI开头,用于多播通信。
可以通过
bash
ifconfig
指令查询主机的MAC地址
局域网传播流程
我们先试着从系统⻆度来理解局域⽹通信原理:
以太⽹中,任何时刻,只允许⼀台机器向⽹络中发送数据
如果有多台同时发送,会发⽣数据⼲扰,我们称之为数据碰撞
所有发送数据的主机要进⾏碰撞检测和碰撞避免• 没有交换机的情况下,⼀个以太⽹就是⼀个碰撞域
局域⽹通信的过程中,主机对收到的报⽂确认是否是发给⾃⼰的,是通过⽬标mac地址判定
我们也可以依赖于这个图来理解:
封装和解包本质上就是压栈和出栈

相关概念:
1. 报头
-
定义:位于数据单元起始部分的控制信息字段,用于指导网络硬件如何处理这个数据单元。
-
特点:
-
固定格式:由协议严格定义(如TCP报头必须包含源端口、目的端口、序列号)。
-
元数据:它是"关于数据的数据",告诉网络设备"我是谁"、"要去哪"、"有多长"、"是否完整"。
-
长度固定或可变:有些协议报头长度固定(如以太网帧头14字节),有些带有选项字段(如IP报头通常是20字节,可扩展到60字节;TCP报头20-60字节)。
-
2. 有效载荷
-
定义:报头之后携带的实际数据,也就是上层协议交付下来的完整协议数据单元。
-
特点:
-
对等性:对当前层来说,有效载荷是透明的(即不需要理解其内容)。例如,IP层看到的有效载荷是一个完整的TCP或UDP报文,它不关心里面是HTTP还是FTP。
-
承载主体:这是通信的"目的",报头只是"手段"。
-
3. 报文
-
定义 :网络中一次通信所传递的一个完整的数据单元,通常包含报头 + 有效载荷 ,有时也包含报尾。
-
泛指与特指:
-
泛指:在任意一层,对PDU(Protocol Data Unit,协议数据单元)的统称。
-
特指:在不同分层中,报文有特定的名称(这在下一节详述)。
-
我们再明确一下不同层的完整报文的叫法
• 不同的协议层对数据包有不同的称谓,在传输层叫做段(segment), 在网络层叫做数据报(datagram) ,在链路层叫做帧(frame) .
• 应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header) ,称为封装(Encapsulation).
• 首部信息中包含了一些类似于首部有多长, 载荷(payload)有多长, 上层协议是什么等信息.
• 数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部, 根据首部中的 "上层协议字段" 将数据交给对应的上层协议处理.
两台主机的TCP/IP的通信为:

数据包封装与分用
数据包封装

数据包分用

跨网络传输的通信流程
IP地址是运行在OSI模型第三层(网络层) 的逻辑地址,用于标识一个节点所属的网络 以及该节点在网络中的主机位置。
目前主流的IP地址类型为IPv4和IPv6。后续我们以IPV4为例。

接下来我们介绍IPv4
IPv4
IPv4地址是一个32位的二进制数,用于唯一标识网络中的一台设备(更准确地说是网络接口)。
-
表示方法 :为了让人容易读写,通常写成点分十进制格式,即将32位二进制每8位(1个字节)一组,分成4组,每组转换为0-255的十进制数,用点隔开。
- 例如:二进制
11000000 10101000 00000001 00001010对应十进制192.168.1.10。
- 例如:二进制
-
层次化构成:IPv4地址由两部分组成,这是它最核心的设计智慧:
-
网络位 :标识设备所在的特定网络。在互联网中,路由器主要靠它来找到目标网络。
-
主机位 :标识在该网络内部的具体设备。

IP网络层存在的意义:提供网络虚拟层,让世界的所有⽹络都是 IP 网络,屏蔽最底层网络的差异。
IP地址与MAC地址的区别
| 对比维度 | MAC地址 | IPv4地址 |
|---|---|---|
| 全称 | 媒体访问控制地址 | 互联网协议第四版地址 |
| 所属层次 | 数据链路层(二层) | 网络层(三层) |
| 本质属性 | 物理地址 / 硬件地址 | 逻辑地址 / 软件地址 |
| 生产/分配方 | 网卡制造商出厂烧录 | 网络管理员或DHCP服务器分配 |
| 可变性 | 理论上固定(可软件欺骗,但硬件不变) | 可变(可动态或静态修改) |
| 长度 | 48位(6字节) | 32位(4字节) |
| 表示格式 | 12位十六进制数(如 00:1A:2B:3C:4D:5E) |
点分十进制(如 192.168.1.10) |
| 地址结构 | 扁平化(无层次,仅标识) | 层次化(网络位 + 主机位) |
| 唯一性范围 | 全球唯一(理论) | 公网唯一 / 私网内唯一 |
| 通信范围 | 局域网内(不可跨路由) | 全球互联网(可路由) |
| 核心作用 | 同一链路内点对点传输数据帧 | 跨网络寻址,标识节点位置 |
| 谁使用它转发 | 交换机(二层转发) | 路由器(三层路由) |
| 比喻类比 | 身份证号(唯一标识你这个人) | 居住地址(告诉别人怎么找到你) |
| 经典问题 | 交换机根据MAC地址表转发帧 | 路由器根据路由表转发数据包 |
Socket编程准备
端口号
端口号是一个16位的无符号整数,用于标识主机上特定的进程或网络服务。它是传输层协议(TCP/UDP)头部中的一个字段。本质上是为了复用和分用。
复用(Multiplexing):发送端的不同应用(如浏览器、邮件客户端)可以同时使用TCP/UDP协议,通过不同的源端口号区分。
分用(Demultiplexing) :接收端的传输层收到数据后,根据目的端口号判断该数据应该交给上层的哪个应用程序(进程)处理。
端口号是16位,取值范围是 0 ~ 65535(2^16共65536个)。IANA(互联网号码分配机构)将其划分为三段,每段具有不同的分配策略和使用场景:
| 范围 | 类别名称 | 取值范围 | 特点与用途 |
|---|---|---|---|
| 熟知端口 | 系统端口/Well-Known Ports | 0 ~ 1023 | 固定分配给系统级核心服务。这些端口由IANA严格控制,通常只有操作系统特权进程(root/管理员)才能使用。它们是互联网上公开约定的标准服务。 |
| 注册端口 | 用户端口/Registered Ports | 1024 ~ 49151 | 分配给用户进程或常见应用。IANA会记录这些端口的用途,但不像熟知端口那样强制。许多商业软件、数据库、非核心服务使用此范围。 |
| 动态/私有端口 | 临时端口/Dynamic/Private Ports | 49152 ~ 65535 | 临时使用,自动分配 。IANA建议将此范围用作客户端的临时端口 。当客户端程序发起连接时,操作系统内核会从此范围内动态选择一个空闲端口作为源端口。 |
工程经验:
-
为什么1024以下是特权端口? 这是出于安全考虑,防止普通用户启动一个服务占用关键的知名端口(如HTTP的80端口),冒充系统服务。
-
实际分配可能重叠:虽然IANA有建议,但在局域网或企业内部,你可以将服务绑定到任何端口(只要不冲突),但公认服务的客户端默认会连接熟知端口。
端口号与进程ID
1. 本质区别
-
进程ID :操作系统分配给每个运行中进程的唯一整数标识 ,用于系统调度和管理(如CPU、内存)。它是系统层的概念。
-
端口号 :网络协议栈用于标识通信端点 的抽象数字,用于网络数据的分用 。它是网络层的概念。
2. 映射关系:N对N
一个进程可以拥有多个端口号 (如一个进程同时监听TCP 80和TCP 443)。
多个进程不能同时绑定到同一个协议+地址+端口组合(TCP和UDP被视为不同的套接字空间,因此可以有一个TCP 53和一个UDP 53共存)。
3. 操作系统如何关联?
当网络数据包到达时,内核的协议栈通过五元组(协议、源IP、源端口、目的IP、目的端口)查找对应的Socket,而每个Socket在创建时与一个进程关联。
-
查看映射的命令:
-
Linux:
netstat -tulnp或ss -tulnp会显示 Local Address:Port 和对应的 PID/Program name。 -
Windows:
netstat -ano显示端口和PID,然后通过任务管理器查看PID对应的进程。
-
源端口号与目的端口号
1. 目的端口号(Destination Port)
-
含义 :标识接收端主机上的目标应用程序。
-
作用 :当数据包到达目的主机时,内核根据目的端口号 决定将数据交给哪个Socket(进程)。对于服务器而言,目的端口通常是熟知端口(如80)。
-
通常固定 :在客户端访问服务时,目的端口是已知的、固定的(如HTTP的80,HTTPS的443)。
2. 源端口号(Source Port)
-
含义 :标识发送端主机上的发起通信的应用程序实例。
-
作用:
-
作为回信地址 :接收方(服务器)处理完请求后,需要向客户端发送响应。服务器从请求包中取出源端口号 ,将其作为响应包的目的端口号,这样才能将响应数据正确返回给发起请求的那个客户端进程(而不是主机上的其他进程)。
-
区分同一主机的多个连接 :如果一个主机同时发起多个到同一服务器(相同目的IP和端口)的连接,每个连接的源端口号 必须是不同的,这样服务器才能通过
(源IP, 源端口)区分不同的会话。
-
-
通常临时 :客户端的源端口通常是操作系统从动态端口范围(49152~65535) 中随机选取的一个临时端口。
3. 通信过程中的角色互换
以访问Web服务器为例:
-
客户端发请求:
-
源IP:
192.168.1.10 -
目的IP:
93.184.216.34(假设为example.com) -
源端口 :
54321(操作系统随机分配的临时端口) -
目的端口 :
80(已知的HTTP服务端口)
-
-
服务器发响应:
-
服务器看到请求包,知道要回复给
192.168.1.10:54321。 -
服务器构造响应包:
-
源IP:
93.184.216.34 -
目的IP:
192.168.1.10 -
源端口 :
80(服务器的端口) -
目的端口 :
54321(从请求包中复制过来的)
-
-
关键在于:服务器响应时的目的端口,就是客户端请求时的源端口。 通过这种方式,客户端的操作系统内核收到响应包后,查看目的端口 54321,就能知道这个数据应该交给当时发起请求的那个浏览器进程(因为那个进程的Socket绑定了本地端口 54321)。
传输层的代表
TCP(传输控制协议)
-
定义 :一种面向连接的、可靠的、基于字节流的传输层协议。
-
设计目标 :在不可靠的IP层之上,为应用层提供一种可靠的、按序的、无差错的数据传输服务。
-
核心思想:通过建立连接、确认应答、重传、排序、流量控制和拥塞控制等机制,将不可靠的IP网络虚拟成一条可靠的传输管道。
UDP(用户数据报协议)
-
定义 :一种无连接的、不可靠的、基于消息的传输层协议。
-
设计目标 :提供一种低延迟、高效率的数据传输方式,将数据交付的责任交给上层应用。
-
核心思想 :在IP层的基础上,仅增加了端口 (用于区分应用)和校验和(用于简单检错),除此之外几乎没有任何额外机制。
| 维度 | TCP | UDP |
|---|---|---|
| 可靠性 | 极高(有确认、重传、校验) | 低(仅校验,无确认重传) |
| 连接性 | 面向连接(三次握手) | 无连接 |
| 数据边界 | 无(字节流) | 有(消息边界) |
| 顺序 | 保证按序 | 不保证 |
| 流量/拥塞控制 | 有 | 无 |
| 首部开销 | 大(20-60字节) | 小(8字节) |
| 传输效率 | 较低 | 高 |
| 广播/多播 | 不支持 | 支持 |
| 典型应用 | HTTP、FTP、SMTP | DNS、VoIP、视频流、游戏 |
网络字节序
字节序 ,也称为端序或尾序,是指多字节数据在计算机内存中存储的顺序,或者通过网络传输时的顺序。由于CPU架构的不同,多字节数据的存储方式主要分为两种:
1. 大端序(Big-Endian)
-
存储方式 :将数据的最高有效字节 (Most Significant Byte, MSB)存储在内存的低地址 处,最低有效字节存储在高地址处。
-
类比 :就像我们书写十进制数
1234,先写最高位1,再写2、3、4。大端序符合人类的阅读习惯。
2. 小端序(Little-Endian)
-
存储方式 :将数据的最低有效字节 (Least Significant Byte, LSB)存储在内存的低地址 处,最高有效字节存储在高地址处。
-
类比 :相当于把数字倒着写,先写最低位
4,再写3、2、1。
为什么需要字节序?
网络是一个异构环境,连接着不同架构的计算机(如x86小端、ARM双端可配置、PowerPC大端等)。如果发送方和接收方采用不同的字节序,且不进行转换,就会发生数据解释错误
为了避免混乱,所有的网络协议在传输多字节数据时,必须规定一个统一的字节序 。TCP/IP协议族选择使用大端序作为网络字节序。这意味着:
-
发送方在发送多字节数据前,必须将数据从主机字节序 转换为网络字节序。
-
接收方在收到数据后,必须将数据从网络字节序 转换回主机字节序,才能正确解析。
网络字节序 (Network Byte Order)就是大端序。这一点在TCP/IP协议设计之初就已确立,并被所有遵循该协议栈的实现所遵守。
-
为什么选择大端序? 这可能与早期TCP/IP实现主要运行在大端的PDP-11等机器上有关,历史原因延续至今。
-
哪些数据需要考虑字节序? 主要是传输层和网络层头部中的多字节数值字段,例如:
-
TCP/UDP端口号(16位)
-
IPv4地址(32位)
-
TCP序列号/确认号(32位)
-
IP数据报长度(16位)
-
ICMP头部中的标识符/序列号(16位)
-
-
单字节数据(如字符)不受字节序影响,因为只有8位,不涉及顺序问题。
总结:
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
• 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存; • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
• TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
• 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
• 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;
常用字节序转换函数
| 函数原型 | 作用 | 说明 |
|---|---|---|
uint32_t htonl(uint32_t hostlong); |
32位主机字节序 → 网络字节序 | 常用于转换IPv4地址 |
uint16_t htons(uint16_t hostshort); |
16位主机字节序 → 网络字节序 | 常用于转换端口号 |
uint32_t ntohl(uint32_t netlong); |
32位网络字节序 → 主机字节序 | 用于解析接收到的IP地址 |
uint16_t ntohs(uint16_t netshort); |
16位网络字节序 → 主机字节序 | 用于解析接收到的端口号 |
命名含义:
-
h:host(主机)
-
n:network(网络)
-
s:short(16位)
-
l:long(32位,在Unix/Linux中long通常为32位)
说明:
头文件 (POSIX 系统):
<arpa/inet.h>或<netinet/in.h>头文件 (Windows 系统):
<winsock2.h>(需链接ws2_32.lib)
1. htonl() ------ 32位主机字节序转网络字节序
-
作用 :将一个32位无符号整数从主机字节序 转换为网络字节序 。常用于转换IPv4地址(
in_addr_t类型)。 -
函数原型:
cpp#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); -
参数:
hostlong:待转换的32位主机字节序整数值。
-
返回值:
-
返回对应的32位网络字节序整数值。
-
输入参数不变,返回值是转换后的结果。
-
注意:
-
尽管函数名包含
l(long),但在所有主流平台上,uint32_t确保为32位,可移植性好。 -
使用示例:
cppstruct in_addr addr; inet_pton(AF_INET, "192.168.1.1", &addr); // addr.s_addr 已是网络字节序 // 若需手动构建,可:addr.s_addr = htonl(0xC0A80101); // 192.168.1.1 的十六进制
2. htons() ------ 16位主机字节序转网络字节序
-
作用 :将一个16位无符号整数从主机字节序 转换为网络字节序。常用于转换TCP/UDP端口号。
-
函数原型:
cpp#include <arpa/inet.h> uint16_t htons(uint16_t hostshort); -
参数:
hostshort:待转换的16位主机字节序整数值(如端口号)。
-
返回值:
- 返回对应的16位网络字节序整数值。
示例:
cpp
uint16_t port = 8080;
uint16_t net_port = htons(port); // 填充 sockaddr_in 时使用 net_port
3. ntohl() ------ 32位网络字节序转主机字节序
-
作用 :将一个32位无符号整数从网络字节序 转换为主机字节序。常用于解析接收到的IPv4地址。
-
函数原型:
cpp#include <arpa/inet.h> uint32_t ntohl(uint32_t netlong); -
参数:
netlong:待转换的32位网络字节序整数值。
-
返回值:
- 返回对应的32位主机字节序整数值。
示例:
cpp
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
getpeername(sockfd, (struct sockaddr*)&cliaddr, &len);
uint32_t host_ip = ntohl(cliaddr.sin_addr.s_addr); // 转换为主机字节序的IP
4. ntohs() ------ 16位网络字节序转主机字节序
-
作用 :将一个16位无符号整数从网络字节序 转换为主机字节序。常用于解析接收到的端口号。
-
函数原型:
cpp#include <arpa/inet.h> uint16_t ntohs(uint16_t netshort); -
参数:
netshort:待转换的16位网络字节序整数值。
-
返回值:
- 返回对应的16位主机字节序整数值。
示例:
cpp
struct sockaddr_in cliaddr;
getpeername(sockfd, ..., &cliaddr);
uint16_t client_port = ntohs(cliaddr.sin_port); // 转换为可打印的端口号
printf("Client port: %d\n", client_port);
socket相关接口
创建端点:socket()
1. 作用
创建一个通信端点,返回一个文件描述符(fd),后续所有操作都通过该描述符进行。它决定了通信所使用的协议族、套接字类型以及具体协议。
2. 表达式
cpp
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
3. 参数选项
-
domain(协议族):-
AF_INET:IPv4 网络协议。 -
AF_INET6:IPv6。 -
AF_UNIX:Unix 域套接字(用于本地进程间通信)。
-
-
type(套接字类型):-
SOCK_STREAM:流式套接字,提供可靠、有序、面向连接的字节流(默认使用 TCP)。 -
SOCK_DGRAM:数据报套接字,提供无连接、不可靠的消息传输(默认使用 UDP)。 -
SOCK_RAW:原始套接字,允许直接操作网络层数据包(需特权)。
-
-
protocol:-
通常设为
0,表示由系统根据domain和type自动选择默认协议(如SOCK_STREAM默认对应IPPROTO_TCP)。 -
也可显式指定,如
IPPROTO_TCP、IPPROTO_UDP或IPPROTO_ICMP。
-
4. 返回值
-
成功 :返回一个非负整数的文件描述符(
sockfd)。 -
失败 :返回
-1,并设置errno以指示错误(如EPROTONOSUPPORT表示协议不支持)。
绑定地址:bind()
1. 作用
将本地协议地址(IP 地址 + 端口号)与一个套接字绑定。对于服务器,这是必须的,以便客户端知道连接到哪里;对于客户端,通常由内核自动分配临时端口,无需显式调用 bind。
2. 表达式
cpp
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
3. 参数选项
-
sockfd:由socket()返回的描述符。 -
addr:指向协议地址结构的指针,需根据协议族强制转换。-
IPv4 使用
struct sockaddr_in,需填充sin_family、sin_port(网络字节序)、sin_addr.s_addr(网络字节序)。 -
IPv6 使用
struct sockaddr_in6。 -
通用地址结构为
struct sockaddr。
-
-
addrlen:地址结构的实际大小(可用sizeof(struct sockaddr_in)等)。
4. 返回值
-
成功 :返回
0。 -
失败 :返回
-1,常见errno包括:-
EADDRINUSE:地址已被占用(可用SO_REUSEADDR选项缓解)。 -
EACCES:权限不足(如绑定特权端口 1-1023)。
-
监听连接:listen()
1. 作用
将一个主动套接字转换为被动套接字,指示内核接受指向该套接字的连接请求。内核会为每个监听套接字维护两个队列:
-
未完成连接队列(SYN_RCVD 状态)
-
已完成连接队列(ESTABLISHED 状态)
2. 表达式
cpp
#include <sys/socket.h>
int listen(int sockfd, int backlog);
3. 参数选项
-
sockfd:已绑定地址的套接字。 -
backlog:已完成连接队列的最大长度(即等待accept的连接数)。若队列满,新的连接请求可能被拒绝或忽略。具体实现可能对backlog有上限(如 Linux 内核参数net.core.somaxconn)。
4. 返回值
-
成功 :返回
0。 -
失败 :返回
-1,常见errno如EOPNOTSUPP(套接字类型不支持监听,如 UDP 套接字)。
接受连接:accept()
1. 作用
从已完成连接队列头部取出一个连接,返回一个全新的套接字描述符(代表与客户端的连接)。原监听套接字保持不变,继续监听。
2. 表达式
cpp
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
3. 参数选项
-
sockfd:监听套接字。 -
addr:指向struct sockaddr的指针,用于返回客户端的协议地址。若不需要,可设为NULL。 -
addrlen:值-结果参数。调用前应初始化为addr所指缓冲区的大小;返回时内核会填充实际地址长度。
4. 返回值
-
成功 :返回一个新的非负整数描述符(
connfd),用于与客户端通信。 -
失败 :返回
-1,常见errno包括:-
EAGAIN/EWOULDBLOCK:非阻塞模式下无新连接。 -
ECONNABORTED:连接中止。 -
EINTR:被信号中断。
-
发起连接:connect()
1. 作用
客户端调用,主动与服务器建立连接。对于 TCP,触发三次握手;对于 UDP,则本地记录服务器地址(不真正建立连接,但可检测一些错误)。
2. 表达式
cpp
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
3. 参数选项
-
sockfd:由socket()返回的套接字(未绑定时内核会隐式绑定一个临时端口)。 -
addr:服务器的协议地址(IP + 端口)。 -
addrlen:地址结构的长度。
4. 返回值
-
成功 :返回
0。 -
失败 :返回
-1,常见errno:-
ETIMEDOUT:连接超时(服务器无响应)。 -
ECONNREFUSED:连接被拒绝(服务器未监听该端口)。 -
ENETUNREACH/EHOSTUNREACH:网络/主机不可达。 -
EINPROGRESS:非阻塞模式下连接尚未完成。
-
发送数据:send() / write() / sendto()
1. 作用
向已连接的套接字发送数据(TCP 或连接型 UDP),sendto 用于无连接 UDP 发送时可指定目标地址。
2. 表达式
cpp
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t write(int sockfd, const void *buf, size_t len); // 通用写函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
3. 参数选项
-
sockfd:已连接套接字(TCP)或任意套接字(UDP)。 -
buf:指向待发送数据的缓冲区。 -
len:数据长度(字节)。 -
flags:控制选项,常用:-
0:默认行为。 -
MSG_DONTWAIT:非阻塞操作。 -
MSG_OOB:发送带外数据。 -
MSG_NOSIGNAL(Linux):写已关闭连接时不产生SIGPIPE信号。
-
-
dest_addr/addrlen:仅用于sendto,指定目标地址。
4. 返回值
-
成功 :返回实际发送的字节数(可能小于
len,需循环发送)。 -
失败 :返回
-1,常见errno:-
EAGAIN/EWOULDBLOCK:发送缓冲区满(非阻塞模式)。 -
EPIPE:对端已关闭连接,产生SIGPIPE(若未忽略或处理)。 -
ECONNRESET:对端异常关闭(收到 RST)。
-
接收数据:recv() / read() / recvfrom()
1. 作用
从套接字接收数据。recvfrom 可获取发送方地址,适用于无连接协议。
2. 表达式
cpp
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t read(int sockfd, void *buf, size_t len);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
3. 参数选项
-
sockfd:已连接套接字或绑定地址的 UDP 套接字。 -
buf:接收缓冲区。 -
len:缓冲区大小。 -
flags:控制选项,常用:-
0:默认。 -
MSG_PEEK:窥探数据但不移出接收队列。 -
MSG_WAITALL:等待直到len字节全部到达(除非出错或中断)。 -
MSG_DONTWAIT:非阻塞。
-
-
src_addr/addrlen:用于recvfrom,返回发送方地址。
4. 返回值
-
成功 :返回实际接收到的字节数。对于 TCP,返回
0表示对端已关闭连接。 -
失败 :返回
-1,常见errno:-
EAGAIN/EWOULDBLOCK:无数据可读(非阻塞)。 -
ECONNRESET:连接被对端重置(收到 RST)。 -
EINTR:被信号中断。
-
关闭连接:close() 与 shutdown()
1. 作用
-
close():将套接字描述符标记为关闭,立即返回。内核会尝试发送待发送数据,然后执行 TCP 四次挥手。当所有引用该套接字的描述符都被关闭后,才会真正释放资源。 -
shutdown():更精细地控制连接关闭,可以单独关闭读、写或读写通道。
2. 表达式
cpp
#include <unistd.h>
int close(int fd);
#include <sys/socket.h>
int shutdown(int sockfd, int how);
3. 参数选项
-
close()只有一个参数fd。 -
shutdown()的how:-
SHUT_RD(0):关闭连接的读半部,后续不能再接收数据。 -
SHUT_WR(1):关闭连接的写半部,后续不能再发送数据(触发 FIN)。 -
SHUT_RDWR(2):同时关闭读写。
-
4. 返回值
-
成功 :返回
0。 -
失败 :返回
-1,设置errno。
常见熟知端口示例(需要熟记)
| 端口号 | 协议 | 服务 | 用途 |
|---|---|---|---|
| 20/21 | TCP | FTP | 文件传输协议(数据/控制) |
| 22 | TCP | SSH | 安全外壳协议(远程登录) |
| 23 | TCP | Telnet | 远程登录(不加密) |
| 25 | TCP | SMTP | 简单邮件传输协议(发邮件) |
| 53 | TCP/UDP | DNS | 域名系统(查询时多用UDP,区域传输用TCP) |
| 67/68 | UDP | DHCP | 动态主机配置协议(服务器/客户端) |
| 80 | TCP | HTTP | 超文本传输协议(网页) |
| 110 | TCP | POP3 | 邮局协议第3版(收邮件) |
| 123 | UDP | NTP | 网络时间协议 |
| 143 | TCP | IMAP | 互联网消息访问协议(收邮件) |
| 161/162 | UDP | SNMP | 简单网络管理协议 |
| 443 | TCP | HTTPS | HTTP over SSL/TLS(安全网页) |
| 3306 | TCP | MySQL | MySQL数据库服务 |
| 3389 | TCP | RDP | Windows远程桌面协议 |
| 6379 | TCP | Redis | Redis缓存数据库 |
| 8080 | TCP | HTTP-Alt | HTTP备用(常用于代理或测试) |
本期关于网络的基础我们就先学到这里,后面我们就会深入学习各种协议
封面图自取:
