目录
- 一、计算机网络的发展背景
- 1、网络的定义
- (1) 独立模式
- (2)网络互联
- 2、局域网 LAN
- 3、广域网 WAN
- 4、比较局域网和广域网
- 5、扩展 —— 域域网和互联网
- 二、初识协议
- 1、协议的概念
- 2、协议的本质
- 3、协议分层
- (1)举例(打电话)
- (2)分层的好处
- (3)封层的依据
- 4、数据传输的条件
- 5、OSI 七层模型
- 6、TCP / IP 五层(或四层)模型
- 三、再识协议
- 1、为什么要有 TCPIP 协议?
- 2、什么是 TCP/IP 协议?
- 3、TCP/IP 协议与操作系统的关系(宏观上,怎么实现的)
- 4、所以究竟什么是协议?
- 四、网络传输基本流程
- 1、网络传输流程
- (1)报头
- (i)什么是报头
- (ii)报头的作用
- (2)局域网通信原理
- (3)以太网和令牌环网
- (i) 以太网
- (ii)令牌环网
- 2、数据包封装和分用
- 五、网络中的地址管理
- 1、认识 IP 地址
- 2、认识 MAC 地址(以太网地址)
- 六、Socket 编程预备
- 1、理解源 IP 地址和目的 IP 地址
- 2、理解源MAC地址和目的MAC地址
- 3、认识端口号
- (1)端口号范围划分
- (2)理解"端口号"和"进程 ID"
- (3)理解源端口号和目的端口号
- (4)理解 socket
- (5)理解socket这个名字
- 4、传输层的典型代表
- (1)认识 TCP 协议
- (2)认识 UDP 协议
- 5、网络字节序
- 6、socket编程接口
- 1、socket常见API
- 2、sockaddr结构
一、计算机网络的发展背景
1、网络的定义
网络是指将多个计算机或设备通过通信线路、传输协议和网络设备连接起来,形成一个相互通信和共享资源的系统。
(1) 独立模式
独立模式 : 计算机之间相互独立。
(2)网络互联
网络互联:多台计算机连接在一起,完成数据共享。
在没有网络的时候,数据也可以进行传输,可以通过使用数据线将两台设备(如计算机、手机或存储设备)直接连接在一起,从而实现数据传输。或者可以通过使用磁带或光盘等媒介来进行数据传输,不过这样传输的成本会比较高。
2、局域网 LAN
相对于广域网 WAN 而言,局域网 LAN 主要是指在相对较小的范围内的计算机互联网络。这个 “小范围” 可以是覆盖一个宿舍,一个办公楼、一所学校等。
局域网的主要特点是:传输速度快、延迟低,并且用于连接同一组织内部的计算机和设备。例如,一家公司内部的多台电脑通过路由器或交换机连接在一起形成的网络就是局域网。
3、广域网 WAN
广域网 WAN 就是我们通常所说的 Internet,是指跨越较大地理范围的计算机网络,它通常由多个局域网或城域网互相连接而成,是一个遍及全世界的网络,将远隔千里的计算机都连在一起。广域网可以覆盖多个城市、省份甚至国家之间的分支机构或办公地点,并且利用互联网等公共网络进行数据传输。广域网允许远程地点的计算机和用户之间实现高速、可靠的连接,以满足远程办公、数据共享和协作等需求。
4、比较局域网和广域网
-
公网、外网,即广域网(WAN)
-
私网、内网,即局域网(LAN)
如何区分它们二者呢?
所谓 “局域网” 和 “广域网” 只是一个相对的概念。比如, 我们有 “天朝特色” 的广域网,也可以看做一个比较大的局域网。如果硬要区分的话可以看路由器,如果没有路由器就是局域网,需要路由器横跨就是广域网。
5、扩展 —— 域域网和互联网
城域网 MAN:城域网是指连接位于同一个城市或者地理范围内的不同机构、公司或校园网络的计算机网络。城域网的覆盖范围比局域网要广,它可以通过光纤、无线电或其他传输介质来连接各个网络设施。城域网的主要特点是传输距离较长,覆盖范围广,一般用于满足互联网接入的需求或者连接企事业单位之间的网络通信。
互联网 Internet:互联网是指全球范围内相互连接的计算机网络。它由无数的局域网、城域网以及广域网组成,通过标准化的通信协议进行数据交换和共享。互联网使得全球各地的计算机和用户能够相互通信、共享信息和资源。它提供了丰富的服务和应用,包括电子邮件、万维网(World Wide Web)、文件传输、远程登录和即时通信等。作为全球最大的计算机网络,互联网已经成为现代社会中不可或缺的一部分。
通过网络,用户可以与他人进行远程通信、获取信息、共享文件和资源等。网络基础设施包括网络协议、路由器、交换机、光纤等技术和设备,它们协同工作以确保数据能够在不同计算机之间传输和交换。
二、初识协议
1、协议的概念
“协议” 是一种约定。协议是指多方之间达成的一种约定或规定,用于指导各方在特定情况下的行为和相互之间的关系。在网络中,为了确保数据传输的有效性、互联互通、统一标准、安全性和资源管理,网络也有属于自己的协议。
高三住校,我打算和父亲用座机联系来表示我想表达的意思,因为用座机接电话会花钱,所以我们就想了一个办法,如果电话响铃一声就挂了表示我向家里报个平安,如果我的生活费不足,需要父亲给我打钱就响铃两声,如果就响三声就表示需要父亲来接我放学回家,这样就减少了成本。
所以这里响几声代表不同的含义,而这个含义不需要解释,双方已经达成了共识,这就叫做约定,而用计算机语言来说这就叫作协议。
举个例子,在计算机中,主机 A 想让主机 B 干一件事,可以先约定好只发送一个字节,不同的比特位代表要做什么事情,这样就可以降低成本,提高效率。
2、协议的本质
计算机之间的传输媒介是光信号和电信号。通过 “频率” 和 “强弱” 来表示 0 和 1 这样的信息。要想传递各种不同的信息就需要约定好双方的数据格式。
只要通信的两台主机约定好协议就可以了吗?
并不是。因为:
- 计算机生产厂商有很多。
- 计算机操作系统也有很多。
- 计算机网络硬件设备也有很多。
他们可能各自有自己的协议。所以,为了让他们之间生产的计算机能够相互顺畅的通信,还需要计算机对应的硬件厂商以同样的规范来处理 0/1 问题。需要约定一个共同的标准,让大家都遵守,这就是网络协议(TCP/IP)。
协议的本质是一层软件层,是为了让双方通信的本质更高效。
计算机的内部有很多组件,比如 CPU、显卡、网卡… 而它们在计算机内部是用线连接起来的。所以,一台计算机的内部本质上也是一个小型的网络结构,计算机内部设备和设备之间也存在协议,比入驱动程序访问硬件就得通过协议。
假设这些线足够长,将硬盘放到几百公里之外,那么现在我们再去存储数据就由原来的写入本地变成通过网络写入远端了,再把 CPU 等都放到远处,就相当于我们把一台计算机的各个功能用多台计算机构建起来,通过网络来进行连接。
所以可以得出结论:在计算机中,体系结构中有网络,网络中有体系结构。
为什么需要协议呢?
因为多台主机的距离较远,为了减少通信成本,所以需要有协议的存在。
通信的复杂问题,本质上是跟距离成正相关的。
3、协议分层
在实际定制网络协议时,是以层状划分的。
为什么要划分为层状结构呢?
- 通信的场景复杂。
- 通过分层可以完成不同协议之间的解耦,也便于人们对其进行各自维护。
(1)举例(打电话)
两个人用电话联系。站在人的角度,是人与人之间在沟通,而站在电话的角度,是电话与电话之间在沟通,这就叫做分层。
在这个例子中, 我们的协议只有两层。 但是实际的网络通信会更加复杂, 需要分更多的层次。分层最大的好处在于 “ 封装” 。
(2)分层的好处
我们把软件进行模块化分,可以很好的进行解耦。解耦之后,我们把通信设备进行更换,比如说用电话进行沟通,上层不需要改变;同样的,上层语言改变,底层不不需要变。所以我们对任何一层进行修改并不会影响到其他层。
(3)封层的依据
把功能比较集中、耦合度较高的的模块放在一层,也就是高内聚。而每一层都是要解决特定的问题。
4、数据传输的条件
从我们的计算机通过网络发送一条信息到你的计算机,如何保证数据在传输过程中不丢失呢?其次,在传输过程中是如何安全找到你的计算机呢?传输过程中是分段传输的,如何解决下一跳主机的问题呢?这其中的复杂性体现在哪?(也就是协议栈要解决的问题)
通信范畴:
处理数据的能力。数据传递过去主机要识别这是什么,然后才能使用这个数据。(应用层)
丢包问题。另一台机器可能没有收到我们所发送的信息。(传输层)
定位问题。有成千上万个主机,需要确定给哪一台机器。(网络层)
解决下一跳问题问题。当两台相离很远的主机之间要传递数据,那么要先有传递一台主机数据的能力(数据包交付能力),然后一台一台的 “蹦” 到目标主机。(数据链路层)
要有纠错的能力。如果出错了就要重新传递一份。(物理层,但不属于软件)
这些都是由不同协议来保证的,而这里的每一层都有自己的协议,每一层协议都解决当前层的问题。
5、OSI 七层模型
OSI把网络从逻辑上分为了七层,每一层都有相关的物理设备。
- OSI(Open System Interconnection,开放系统互连)七层网络模型称为开放式系统互联参考模型,是一个逻辑上的定义和规范。
- 把网络从逻辑上分为了 7 层。每一层都有相关、相对应的物理设备,比如路由器,交换机。
- OSI 七层模型是一种框架性的设计方法,其最主要的功能使就是帮助不同类型的主机实现数据传输。
- 它的最大优点是将服务、接口和协议这三个概念明确地区分开来,概念清楚,理论也比较完整。通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯。但是,它既复杂又不实用,所以下面就按照 TCP/IP 四层模型来讲述。在工程实践中把应用层表示层和会话层压缩成一层。
其实在网络角度,OSI定的协议7层模型其实非常完善,但是在实际操作的过程中,会话层、表示层是不可能接入到操作系统中的,所以在工程实践中,最终落地的是5层协议。
但是要理解上面的话,需要我们学习完网络才可以理解,这里就知道就可以。
6、TCP / IP 五层(或四层)模型
TCP/IP 是一组协议的代名词,它还包括许多协议,组成了 TCP/IP 协议簇。
TCP/IP 通讯协议采用了 5 层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
物理层: 负责光/电信号的传递方式。比如现在以太网通用的网线(双绞线)、早期以太网采用的的同轴电缆(现在主要用于有线电视)、光纤,现在的 wifi 无线网使用电磁波等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等。集线器(Hub)工作在物理层。
数据链路层: 负责设备之间的数据帧的传送和识别. 例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作。有以太网、令牌环网,无线LAN等标准。交换机(Switch)工作在数据链路层。
网络层: 负责地址管理和路由选择。例如在 IP 协议中,通过 IP 地址来标识一台主机, 并通过路由表的方式规划出两台主机之间的数据传输的线路(路由)。路由器(Router)工作在网路层。
传输层: 负责两台主机之间的数据传输. 如传输控制协议 (TCP),能够确保数据可靠的从源主机发送到目标主机。
应用层: 负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。我们的网络编程主要就是针对应用层。
前面讲到的数据传输的条件,数据链路层解决的是能够传递的问题,网络层解决的是选择路径的问题,传输层解决的是纠错的问题,而应用层就是解决数据解析的问题。
物理层我们考虑的较少,因此很多时候也可以称为 TCP/IP 四层模型。
一般而言,
- 对于一台主机,它的操作系统内核实现了从传输层到物理层的内容。
- 对于一台路由器,它实现了从网络层到物理层。
- 对于一台交换机,它实现了从数据链路层到物理层。
- 对于集线器,它只实现了物理层。
但是并不绝对,很多交换机也实现了网络层的转发,很多路由器也实现了部分传输层的内容(比如端口转发)。
注意: 数据链路层中的网卡层是驱动程序的一部分。
网络层和传输层是操作系统内部自己实现的。所有的操作系统都一样,所以全球的主机都能互联。
OS层次图:
可以看到跟上面讲的没什么区别。在应用层传输层时间会有系统调用接口,主要是文件类的系统调用接口。
注意: TCP 和 IP 各自是传输层和网络层最具代表性的两个协议,这个协议栈命名为 TCP/IP 模型,足以看出这两个协议的重要性,它们的重要性是操作系统赋予的。
三、再识协议
上面的内容,我们只是懂了一些基本概念,还是达不到我们的目标,下面我们再次重新理解协议和协议分层。
1、为什么要有 TCPIP 协议?
-
首先,即便是单机,你的计算机内部,其实都是存在协议的,比如:其他设备和内存通信,会有内存协议。其他设备和磁盘通信,会有磁盘相关的协议,比如:SATA,IDE,SCSI等。只不过我们感知不到罢了。而且这些协议都在本地主机各自的硬件中,通信的成本、问题比较少。
-
其次,网络通信最大的特点就是主机之间变远了。任何通信特征的变化,一定会带来新的问题,有问题就得解决问题,所以需要新的协议咯。
所以,为什么要有 TCP/IP 协议?本质就是通信主机距离变远了
2、什么是 TCP/IP 协议?
- TCP/IP 协议的本质是一种解决方案
- TCP/IP 协议能分层,前提是因为问题们本身能分层
3、TCP/IP 协议与操作系统的关系(宏观上,怎么实现的)
4、所以究竟什么是协议?
- 截止到目前,我们还没接触过任何协议,但是如何朴素的理解协议,我们已经可以试试了。
- OS 源代码一般都是用 C/C++语言写的。
下面,仔细看看下面的图
四、网络传输基本流程
1、网络传输流程
局域网中同一个网段内的两台主机是可以直接进行通信(文件传输)的。
跨网段的主机的文件传输,数据从一台计算机到另一台计算机传输过程中要经过一个或多个路由器。
前面讲到的层状结构,每一层都会有协议,而每一个协议的最终表现就是报头。
举个生活中的例子,网购时,商家需要将物品送到我们手上,但并不是他们亲自派送,而是交给快递公司,这就体现了分层的思想:
我们收件的时候不会单单只收到物品,还有快递盒和快递单。这个多出来的快递单就叫做报头。
同样,现在我们需要发数据,发送的数据可能比我们想要的要多一点,那么这多出来的一部分就是报头。那这个快递单号又是给谁看的呢?是给快递员看的,这个快递单就是快递公司自己定的协议,这个快递单子在它们的物流体系中都能够被识别。所以,协议通常是通过协议报头来表达的,每一份数据在每一层都要有自己的报头。
客户在应用层发送数据,为了数据的安全、完整和网络之间的路径选择等问题,必须自顶向下经过应用层、传输层、网络层、链路层,再通过局域网发送给对方。每层都有自己的协议定制方案,每层协议都要有自己的协议报头,从上到下交付数据时时,都会添加对应的报头。
一个设备至少要横跨两个网络,才能实现数据包跨网络转发,所以路由器必须要横跨两个网络,也就是必须有两张网卡。
(1)报头
(i)什么是报头
在计算机网络通信中,报头(Header)是一部分数据包的固定结构,它包含了关于该数据包的元信息和控制信息。报头位于数据包的前部,用于标识和管理数据包的传输。
- 报头通常由多个字段组成,每个字段用于存储特定类型的信息。下面是一些常见的报头字段及其功能:
- 目标地址字段:指示接收数据包的目标设备或主机的地址。这个地址可以是物理地址(如:MAC 地址)或逻辑地址(如:IP 地址)。
- 源地址字段:标识发送数据包的源设备或主机的地址。
- 协议字段:指示数据包使用的协议类型,例如 TCP(传输控制协议)或 UDP(用户数据报协议)。
- 长度字段:指明整个数据包的长度,包括报头和数据部分。
- 校验和字段:用于校验数据包在传输过程中是否出现了错误。接收端可以通过计算校验和来验证数据包的完整性。
- 服务质量字段:用于指示数据包的优先级和处理要求,例如差错检测、传输延迟、带宽需求等。
- 标记字段:存储一些额外的控制或标识信息,用于特定的协议或网络处理。
简单来说,协议报头就是收到的报文当中多出来的内容。
(ii)报头的作用
报头在通信协议中的作用非常重要,它承载了传输过程中所需的元信息和控制信息。
- 标识和定位:报头中的目标地址字段和源地址字段用于标识和定位数据包的接收方和发送方。通过指定目标地址,数据包可以准确地传递给目标设备或主机。
- 数据处理和路由:报头中的协议字段指明了数据包所使用的传输协议,如 TCP、UDP 等。不同的协议可能需要进行不同的数据处理和路由方式,因此报头能够帮助网络设备正确地处理和路由数据包。
- 错误检测和纠正:校验和字段可以用于验证数据包在传输过程中是否出现了错误。接收端可以通过计算校验和来检测数据包的完整性,并且对于出现错误的情况,一些纠错技术可以根据校验和字段的信息来恢复原始数据。
- 服务质量管理:报头中的服务质量字段可以指示数据包的优先级和处理要求。这有助于网络设备在网络拥塞或负载高的情况下,根据不同的服务质量需求进行优先级处理,保证关键数据的传输效果。
- 特定协议需求:某些协议可能需要特定的控制或标识信息来辅助数据包的处理和传输。报头中的标记字段可以承载这些额外的控制信息,以满足特定协议的需求。
通过解析报头中的字段信息,网络设备和计算机能够理解和处理数据包,识别其源和目标,并根据需要采取适当的操作,比如路由转发、错误检测、数据重组等。报头在网络通信中起着非常重要的作用,确保数据包按照正确的方式传输并被正确处理。
添加报头的原因如下:
- 数据识别和标识:在数据传输中,报头 (Header) 包含关于数据的元信息,比如数据类型、数据长度、传输协议等。通过添加报头,可以对数据进行识别和标识,确保接收方能够正确地解析和处理数据。
- 协议规范:不同的数据传输协议通常会规定报头的格式和内容,以便确保传输的正确性和可靠性。报头中可能包含有关源地址、目标地址、校验位等必要信息,这些信息使得数据能够按照协议规范进行有效的传输。
- 数据完整性校验:在数据传输过程中,为了确保数据的完整性,通常会使用校验和或哈希值等方式对数据进行校验。报头中可以包含校验和或哈希值等信息,接收方在接收到数据后可以根据报头中的校验信息验证数据的完整性,以避免数据损坏或篡改的情况。
- 数据流控制和错误处理:报头中可能还会包含有关数据流控制和错误处理的信息,比如序列号、确认号等。这些信息可以用于在数据传输过程中进行流量控制、处理丢包和重传等情况,从而提高数据传输的可靠性和效率。
(2)局域网通信原理
两台局域网的主机是能够直接通信的。
在讲原理之前先引入一个概念:
每一台主机都有自己的网卡,每一张网卡都有自己的地址,叫做 MAC 地址。就像我们的身份证一样,标识网卡的唯一性。而 MAC 地址虽然全球唯一,但是不应用于全球,只是在局域网中标识自己的唯一。
指令:ifconfig
这里的 MAC 地址是个虚拟地址。
在局域网中有很多主机:
现在 MAC3 想要跟 MAC5 发送消息时,其他所有主机都能收到,但是其他主机在做协议判断发现并不是发给自己的,就会自动丢弃。
(3)以太网和令牌环网
(i) 以太网
以太网就是一种具体的局域网。
以太网的通信方式就是上面局域网这种通信的方式:发出的消息所有人都能收到。
但是当 MAC3 想把消息发给 MAC5,MAC2 想把消息发给 MAC7时,它们不能同时发消息,因为数据会覆盖,所以以太网发送消息的原则是只允许一个主机在任何一个时刻在局域网中发消息。否则就会发生碰撞,如果发生了碰撞就把消息作废然后重发。站在系统的角度看待网络资源就是临界资源。
(ii)令牌环网
令牌环网的解决方式就是谁持有令牌环谁发送数据。没有令牌的主机就不能发送消息。就类似于系统中的锁。
2、数据包封装和分用
假设现在有两个人在用 QQ 进行聊天,站在他们的角度,他们会认为他们是在用户层直接进行聊天,而实际上却是数据向下交付(封装)在向上解包(分用)才实现的聊天。
数据包封装: 在向下交付的时候每一层都会添加自己的报头,报文 = 报头 + 有效载荷,再把报文向下交付。
- 报头部分,就是对应协议层的结构体字段,我们一般叫做报头
- 除了报头,剩下的叫做有效载荷
- 故,报文=报头+有效载荷
数据包分用: 在向上解包时,因为同一层有相同的协议,所以能识别报头,它会解开报头,把有效载荷分离,再向上解包。这样就形成了对称的结构。
可以看到同层报头和有效载荷完全一样,左边如何发的,右边就是如何收到的,那么就可以认为是在同层协议中直接通信,也可以理解为向下交付。
它的流程图是这样,在路由器部分传递给令牌环驱动程序的时候,加上的报头就是令牌环协议(重新封装),这样就跟左边不一样了,但是不影响上面的对称性。
可以得出 IP 层的作用就是屏蔽底层网络的差异。
而对于不同网段的两台计算机通讯过程略有不同,不同的地方就在路由器部分:
将自顶向下进行交付的过程称为封装,封装就是添加报头的过程。
解包的本质就是去掉报头,展开分析。
然后,我们在明确一下不同层的完整报文的叫法
- 不同的协议层对数据包有不同的称谓,在传输层叫做数据段(segment),在网络层叫做数据报(datagram),在链路层叫做数据帧(frame)。
- 应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(报头(header)),称为封装(Encapsulation)。
- 首部信息中包含了一些类似于首部有多长, 载荷(payload)有多长, 上层协议是什么等信息.
- 数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,根据首部中的 “上层协议字段” 将数据交给对应的上层协议处理。
下图为数据封装的过程:
下图为数据分用的过程:
五、网络中的地址管理
MAC 地址通常在局域网使用,IP 地址通常在广域网使用。
1、认识 IP 地址
IP 地址(Internet Protocol Address)是用于在互联网上唯一标识和定位设备的一组数字。由 32 位二进制数或 4 个八位二进制数组成的十进制数表示。
它分为两部分:网络地址和主机地址,网络地址用于标识所连接的网络,而主机地址则用于标识具体的设备。IP 地址用于在网络上进行数据包的传输和路由选择。
当你连接到互联网上时,你的设备会被分配一个 IP 地址,以便在网络中唯一标识和定位你的设备。IP 协议有两个版本,IPv4 和 IPv6。后面凡是提到 IP 协议,没有特殊说明的,默认都是指 IPv4。以下是两个示例 IP 地址的解释:
- IPv4 地址:192.168.0.1 这是一个常见的 IPv4 地址格式。对于 IPv4 来说,IP 地址是一个 4 字节,32 位的整数。它由四个八位二进制数组成,通过 “点分十进制” 的字符串表示。在这个示例中,192.168.0.1 是一个 IP 地址,其中 192.168.0 表示网络地址部分,而 1 则表示主机地址部分。其中,用点分割的每一个数字表示一个字节,范围是:0~255。这个 IP 地址可能用于一个局域网中的路由器或计算机。
- IPv6 地址:2001:0db8:85a3:0000:0000:8a2e:0370:7334 IPv6 地址是下一代 IP 地址标准,是一个 16 字节,128 位的二进制数,并使用冒号分隔。在这个示例中,2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个 IPv6 地址,它包含了网络地址和主机地址信息。IPv6 地址的主要目的是扩展互联网的地址空间,以支持未来更多的设备连接。
上面这些是示例 IP 地址。实际上,每个设备在网络中都有一个唯一的 IP 地址,以便进行通信和数据传输。在使用 TCP/IP 协议的网络中,IP 及其向上的协议看到的报文都是一样的。
2、认识 MAC 地址(以太网地址)
MAC 帧地址(Media Access Control Address)也称为物理地址或硬件地址,用来识别数据链路层中相连的节点。它是一个用于在局域网中唯一标识网络适配器(如:网卡)的长度为 48 位(即 6 个字节)的二进制数。一般用 16 进制数字加上冒号的形式来表示(例如:08:00:27:03:fb:19)
每个网络适配器都有一个唯一的 MAC 地址(虚拟机中的 mac 地址不是真实的 mac 地址,可能会冲突,也有些网卡支持用户配置 mac 地址),它由厂商在生产时烧录到适配器中,在网卡出厂时就确定了,不能修改。MAC 帧地址用于在局域网中寻找目标设备,它是数据链路层的一部分,用于将数据包从源设备传输到目标设备。在以太网中,MAC 地址是数据包在局域网中传输所必需的信息。
举例说明 MAC 帧地址的结构和作用,假设有两台计算机 A 和 B 进行通信:
计算机 A 的网卡上配置了 MAC 地址为 00:11:22:33:44:55,计算机 B 的网卡上配置了 MAC 地址为 AA:BB:CC:DD:EE:FF。当计算机 A 希望将数据包发送到计算一个以太网帧,并包含以下字段:
- 目标 MAC 地址:设置为计算机 B 的 MAC 地址(AA:BB:CC:DD:EE:FF)。
- 源 MAC 地址:设置为计算机 A 的 MAC 地址(00:11:22:33:44:55)。
- 其他帧头字段(例如帧类型等)和数据。
计算机 A 将该帧发送到网络,经过交换机等设备转发,最终到达计算机 B 的网卡。计算机 B 接收到该帧后,会检查目标 MAC 地址与自己的 MAC 地址是否匹配。如果匹配,则认为该帧是发给自己的,继续解析帧中的其他字段和数据。
通过这个过程,MAC 帧地址起到了两个重要的作用:
- 唯一标识设备:每个网络设备(如网卡)都有一个唯一的 MAC 地址,用于在局域网中识别和寻址设备。这是因为以太网是一个共享介质的网络,通过 MAC 地址可以准确地将数据包传送到目标设备。
- 确保交付:通过将目标MAC地址设置为接收方的 MAC 地址,数据包可以被有针对性地转发到正确的设备,确保数据包的正确交付。
既然这两个都能表示地址,那么为什么要搞两个地址呢?
举个例子帮助理解:在西游记中,唐僧每经过一个国家的时候,会跟当地的人说:贫僧从东土大唐而来,去往西天拜佛取经。当地人就会问他从哪里来的,再告诉他接下来要去哪(这个过程就叫作路由的过程,路由的本质就是根据目的地来选择下一站去哪)。比如说,上一站是车迟国,下一站要去黑风岭。这里的东土大唐和西天就是源 IP 地址,自始至终都不会改变,而黑风岭(下一站地址)是源 MAC 地址,一直在变化。
- IP 地址提供的是方向。
- MAC 地址提供的是可行路径。
注意: 这里的 MAC 两个地址一定是挨着的,所以是同一个局域网。
下图为结合IP与MAC的通信过程:
六、Socket 编程预备
1、理解源 IP 地址和目的 IP 地址
- IP在网络中,用来标识主机的唯一性
- 注意:后面我们会讲IP的分类,后面会详细阐述IP的特点
但是这里要思考一个问题:数据传输到主机是目的吗?不是的。因为数据是给人用的。比如:聊天是人在聊天,下载是人在下载,浏览网页是人在浏览?但是人是怎么看到聊天信息的呢?怎么执行下载任务呢?怎么浏览网页信息呢?通过启动的 qq,迅雷,浏览器。
而启动的 qq,迅雷,浏览器都是进程。换句话说,进程是人在系统中的代表,只要把数据给进程,人就相当于就拿到了数据。
所以:数据传输到主机不是目的,而是手段。到达主机内部,在交给主机内的进程才是目的。
但是系统中,同时会存在非常多的进程,当数据到达目标主机之后,怎么转发给目标进程?这就要在网络的背景下,在系统中,标识主机的唯一性。
2、理解源MAC地址和目的MAC地址
大部分数据的传输都是跨局域网的,数据在传输过程中会经过若干个路由器,最终才能到达对端主机。
源MAC地址和目的MAC地址是包含在链路层的报头当中的,而MAC地址实际只在当前局域网内有效,因此当数据跨网络到达另一个局域网时,其源MAC地址和目的MAC地址就需要发生变化,因此当数据达到路由器时,路由器会将该数据当中链路层的报头去掉,然后再重新封装一个报头,此时该数据的源MAC地址和目的MAC地址就发生了变化。
例如,在图中主机1向主机2发送数据的过程中,数据的源MAC地址和目的MAC地址的变化过程如下:
时间轴 | 源MAC地址 | 目的MAC地址 |
---|---|---|
刚开始 | 主机1的MAC地址 | 路由器A的MAC地址 |
经过路由器A之后 | 路由器A的MAC地址 | 路由器B的MAC地址 |
经过路由器B之后 | 路由器B的MAC地址 | 路由器C的MAC地址 |
经过路由器C之后 | 路由器C的MAC地址 | 路由器D的MAC地址 |
经过路由器D之后 | 路由器D的MAC地址 | 主机2的MAC地址 |
因此数据在传输的过程中是有两套地址:
- 一套是源IP地址和目的IP地址,这两个地址在数据传输过程中基本是不会发生变化的(存在一些特殊情况,比如在数据传输过程中使用NET技术,其源IP地址会发生变化,但至少目的IP地址是不会变化的)。
- 另一套就是源MAC地址和目的MAC地址,这两个地址是一直在发生变化的,因为在数据传输的过程中路由器不断在进行解包和重新封装。
3、认识端口号
- 端口号(port)是传输层协议的内容;
- 端口号是一个2字节 16 位的整数;
-端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理; - IP地址+端口号能够标识网络上的某一台主机的某一个进程;
- 一个端口号只能被一个进程占用。
(1)端口号范围划分
- 0-1023: 知名端口号, HTTP,FTP,SSH 等这些广为使用的应用层协议,他们的端口号都是固定的。
- 1024-65535:操作系统动态分配的端口号.客户端程序的端口号,就是由操作系统从这个范围分配的。
(2)理解"端口号"和"进程 ID"
我们之前在学习系统编程的时候,学习了 pid 表示唯一一个进程;此处我们的端口号也是唯一表示一个进程.那么这两者之间是怎样的关系?
另外,一个进程可以绑定多个端口号;但是一个端口号不能被多个进程绑定;
进程 ID 属于系统概念,技术上也具有唯一性,确实可以用来标识唯一的一个进程,但是这样做,会让系统进程管理和网络强耦合,实际设计的时候,并没有选择这样做。
(3)理解源端口号和目的端口号
传输层协议(TCP 和 UDP)的数据段中有两个端口号,分别叫做源端口号和目的端口号,就是在描述"数据是谁发的,要发给谁"。
(4)理解 socket
- 综上,IP地址用来标识互联网中唯一的一台主机,port 用来标识该主机上唯一的一个网络进程
- IP+Port 就能表示互联网中唯一的一个进程
- 所以,通信的时候,本质是两个互联网进程代表人来进行通信,{srclpsrcPort,dstlp,dstPort}这样的4元组就能标识互联网中唯二的两个进程
- 所以,网络通信的本质,也是进程间通信。也就是说,socket通信本质上就是两个进程之间在进行通信,只不过这里是跨网络的进程间通信。比如逛淘宝和刷抖音的动作,实际就是手机上的淘宝进程和抖音进程在和对端服务器主机上的淘宝服务进程和抖音服务进程之间在进行通信。
- 我们把ip+port 叫做套接字 socket
(5)理解socket这个名字
socket在英文上有“插座”的意思,插座上有不同规格的插孔,我们将插头插入到对应的插孔当中就能够实现电流的传输。
在进行网络通信时,客户端就相当于插头,服务端就相当于一个插座,但服务端上可能会有多个不同的服务进程(多个插孔),因此当我们在访问服务时需要指明服务进程的端口号(对应规格的插孔),才能享受对应服务进程的服务。
4、传输层的典型代表
如果我们了解了系统,也了解了网络协议栈,我们就会清楚,,传输层是属于内核的,那么我们要通过网络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行的网络通信。
(1)认识 TCP 协议
此处我们先对TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识后面我们再详细讨论TCP 的一些细节问题。
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
(2)认识 UDP 协议
此处我们也是对 UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识;后面再详细讨论。
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
因为我们暂时还没有深入了解 tcp、udp协议,此处只做了解即可
5、网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分.那么如何定义网络数据流的地址呢?
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出。
- 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存。
- 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
- TCP/IP 协议规定,网络数据流应采用大端字节序,即低地址高字节。
- 不管这台主机是大端机还是小端机,都会按照这个 TCP/IP 规定的网络字节序来发送/接收数据。
- 如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
- 这些函数名很好记,h 表示 host,n 表示 network,|表示 32 位长整数,s 表示 16 位短整数。
- 例如 htonl 表示将 32 位的长整数从主机字节序转换为网络字节序,例如将 IP 地址转换后准备发送。
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
- 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
6、socket编程接口
1、socket常见API
创建套接字:(TCP/UDP,客户端+服务器)
int socket(int domain, int type, int protocol);
第一个参数domain:我们把他叫做域,或者叫做协议家族的类型
第二个参数type:表示套接字类型,同样可以用man查看。
第三个参数protocol:表示创建的套接字的传输层类型,是tcp还有udp,一般默认为0就行
绑定端口号:(TCP/UDP,服务器)
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
第一个参数:表示socket创建成功后返回的fd
监听套接字:(TCP,服务器)
int listen(int sockfd, int backlog);
接收请求:(TCP,服务器)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
建立连接:(TCP,客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
2、sockaddr结构
套接字不仅支持跨网络的进程间通信,还支持本地的进程间通信(域间套接字)。在进行跨网络通信时我们需要传递的端口号和IP地址,而本地通信则不需要,因此套接字提供了sockaddr_in结构体和sockaddr_un结构体,其中sockaddr_in结构体是用于跨网络通信的,而sockaddr_un结构体是用于本地通信的。
为了让套接字的网络通信和本地通信能够使用同一套函数接口,于是就出现了sockeaddr结构体,该结构体与sockaddr_in和sockaddr_un的结构都不相同,但这三个结构体头部的16个比特位都是一样的,这个字段叫做协议家族。
此时当我们在传递在传参时,就不用传入sockeaddr_in或sockeaddr_un这样的结构体,而统一传入sockeaddr这样的结构体。在设置参数时就可以通过设置协议家族这个字段,来表明我们是要进行网络通信还是本地通信,在这些API内部就可以提取sockeaddr结构头部的16位进行识别,进而得出我们是要进行网络通信还是本地通信,然后执行对应的操作。此时我们就通过通用sockaddr结构,将套接字网络通信和本地通信的参数类型进行了统一。
注意: 实际我们在进行网络通信时,定义的还是sockaddr_in这样的结构体,只不过在传参时需要将该结构体的地址类型进行强转为sockaddr*罢了。
sockaddr 结构
sockaddr_in 结构
虽然 socket api 的接口是 sockaddr, 但是我们真正在基于 IPv4 编程时, 使用的数据结构是 sockaddr_in, 这个结构里主要有三部分信息: 地址类型, 端口号, IP 地址。
in_addr 结构
in_addr 用来表示一个 IPv4 的 IP 地址,其实就是一个 32 位的整数。