网络:基础概念
网络:基础概念
在计算机发展过程中,最开始每个计算机时相互独立的,后来人们需要用计算机合作处理任务,这就牵扯到了数据交换,所以最开始的网络就诞生了。一开始,网络都是局域网LAN
,后来技术成熟,计算机设备增多,广域网WAN
就来了。这里的局域网和广域网都是一个相对的概念。
计算机作为人的工具,人要协同工作,者注定了网络必然产生。一切都是最好的安排。
协议
协议就是通信双方约定好的通信方式
一开始,计算机都是在局域网中进行数据通信,各个局域网都有自己的通信标准(协议)。后来一些比较权威的组织,开始制定详尽的协议
国际标准化组织:
IEEE(电气和电子工程师协会):这是一个由计算机和工程领域专家组成的庞大技术组织,在通信协议领域贡献突出。
IEEE
制定了全世界电子、电气和计算机科学领域 30%左右的标准,包括 IEEE 802 系列标准,这些标准涵盖了从局域网(LAN)到广域网(WAN)等多种网络技术。ISO(国际标准化组织):
ISO
是由多个国家的标准化团体组成的国际组织,它在开放系统互连(OSI)模型方面的工作尤为著名。OSI
模型定义了网络通信的七层协议结构,尽管在实际应用中,TCP/IP
协议族更为普遍,但OSI
模型仍然在学术和理论研究中占有重要地位。ITU(国际电信联盟):
ITU
是联合国下属的专门机构,负责制定电信领域的国际标准。ITU-T
制定的标准涵盖了电话和网络通信,与ISO
合作确保了通信技术的全球兼容性和互操作性。区域标准化组织:
ETSI(欧洲电信标准学会):由欧洲共同体各国政府资助,是一个由电信行业的厂商与研究机构参加并从事研究开发到标准制定的组织。
ASTAP(亚洲与泛太平洋电信标准化协会):1998 年由日本与韩国发起成立的标准化组织,旨在加强亚洲与太平洋地区各国信息通信基础设施及其相互连接的标准化工作的协作。
公司:某些公司,如泰凌微,也自研各种标准的软件协议栈,包括低功耗蓝牙、
zigbee
、thread
及Matter
等,并可进行定制化改动,这是其核心竞争力之一。泰凌微还计划重点发展智能电子价签、智能遥控、智能家居等市场。民间国际团体:
IETF(互联网工程师任务组):这是一个负责开发和推广互联网协议(特别是构成
TCP/IP
协议族的协议)的志愿组织,通过 RFC 发布新的或者取代老的协议标准官方机构:
FCC(联邦通信委员会):美国对通信技术的管理的官方机构,主要职责是通过对无线电、电视和有线通信的管理来保护公众利益。也对包括标准化在内的通信产品技术特性进行审查和监督。
OSI七层网络协议模型
软件分层是为了更好的解耦,降低维护成本
OSI(
Open System Interconnection
,开放系统互连)七层网络模型称为开放式系统互联参考模型,是一个逻辑上的定义和规范; 把网络从逻辑上分为了 7 层. 每一层都有相关、相对应的物理设备,比如路由器,交换机OSI 七层模型是一种框架性的设计方法,其最主要的功能使就是帮助不同类型的主机实现数据传输
它的最大优点是将服务、接口和协议这三个概念明确地区分开来,概念清楚,理论也比较完整. 通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯
为了降低学习成本,我们将它简化,按照
TCP/IP
四层模型来讲解
在网络角度,OSI
定制的七层模型非常完善,但是在实操过程中,会话层,表示层是不可能接入到OS
中的,所以在工程实践中,在最终落地的是五层协议,数据链路层下面还有一个物理层
物理层: 负责光/电信号的传递方式. 比如现在以太网通用的网线(双绞线)、早期以太网采用的的同轴电缆(现在主要用于有线电视)、光纤, 现在的
wifi
无线网使用电磁波等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等。集线器(Hub)工作在物理层。数据链路层: 负责设备之间的数据帧的传送和识别。例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作。有以太网、令牌环网,无线
LAN
等标准. 交换机(Switch)工作在数据链路层。网络层: 负责地址管理和路由选择。例如在
IP
协议中,通过IP
地址来标识一台主机, 并通过路由表的方式规划出两台主机之间的数据传输的线路(路由)。路由器(Router)工作在网路层。传输层: 负责两台主机之间的数据传输。如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到目标主机。
应用层: 负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。我们的网络编程主要就是针对应用层。
设备 | 实现的网络层次(OSI 模型) | 核心功能举例 |
---|---|---|
主机(内核) | 传输层、网络层、数据链路层(软件) | TCP 通信、IP 路由、Ethernet 帧处理 |
路由器 | 网络层、数据链路层、物理层 | IP 转发、跨网络互联 |
交换机 | 数据链路层、物理层 | MAC 地址转发、局域网内通信 |
集线器 | 物理层 | 电信号放大与广播 |
协议的本质
协议就是双方的一种规定,就像摩斯密码就是一种协议,通过规定某些行为来通过这些行为来传递信息。在语言层面,由于从传输层到网卡驱动层都是嵌入在操作系统中的。而操作系统又是C/C++
写的,所以协议的本质就是通信双方都认识的结构化的数据类型。
协议是分层的,所以网络中的每层都有协议,同层之间,互相都有可以认识对方的协议。
网络传输基本流程
局域网传输流程
两台主机在同一个局域网内是能够直接通信的,每台主机在局域网中都有一个标识来保证主机的唯一性:mac
地址(这货实际上也是全球唯一,但由于历史原因,mac
地址是在ip
地址后面发明的)
MAC地址
MAC
地址用来识别数据链路层中相连的节点长度位48位,及6个字节,一般用16进制数字加上冒号的形式来表示
08:00:27:03:fb:19
MAC
地址在网卡出厂时就确定了,不能修改,MAC
地址通常是唯一的(虚拟机中的MAC
地址不是真实的MAC
地址,可能会冲突;也有些网卡支持用户配置MAC
地址)
以太网中,任何时刻,只允许一台主机向网络中发送数据,如果有多台同时发送,会发生数据干扰,称之为数据碰撞。所有发送数据的主机要进行碰撞检测和碰撞避免。在没有交换机的情况下,一个局域网就是一个碰撞域(所以现在你知道同一个局域网下设备多了网卡的原因了吗?)局域网通信中主机对收到的报文确认是否是发给自己的,是通过目标MAC
地址来判定的
- 首先,我们要明确
报文 = 有效载荷 + 报头
。然后,我们在明确一下不同层的完整报文的叫法 - 不同的协议层对数据包有不同的称谓,在传输层叫做段
segment
,在网络层叫做数据报datagram
,在链路层叫做帧frame
- 应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部
header
,称为封装Encapsulation
- 首部信息中包含了一些类似于首部有多长, 载荷
payload
有多长,上层协议是什么等信息 - 数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,根据首部中的“上层协议字段”将数据交给对应的上层协议处理
在网络通信过程中,数据不是直接发送给对方主机的,而是先要自顶向下将数据交付给下层协议,最后由底层发送,然后由对方主机的底层接收,再自底向上交付
要学习一种协议,就是学习这个协议是工作在那一层的,它是如何封包,如何解包,如何分用,还有它是如何将自己的有效载荷交付给上层协议的
跨网络传输流程
IP地址
IP
协议有两个版本,IPV4
和IPV6
,后者目前应用不多(中国在IPV6
技术上是Top
)所以我们先学前者
- IP地址是在IP协议中,用来标识网络中不同主机的地址
- 对于IPV4来说,IP地址是一个4字节,32位的整数
- 我们通常也使用“点分十进制”的字符串表示 IP 地址,例如
192.168.0.1
用点分割的每一个数字表示一个字节,范围是 0 - 255
跨网段的主机数据传输,数据从一台计算机到另外一台计算机传输过程中要经过一个或多个路由器
因为目标主机和本主机不在同一个子网(局域网),而路由器又有构建子网的能力,所以一个路由器一般都有两套网卡,两个IP地址,用于构建两个子网。所以当当前主机和目标主机不在同一个子网下时,数据要去到目标主机就要先去路由器,经过路由转发到目标主机的子网,再将数据交给目标主机。
IP
地址在整个路由过程中,一直不变 TODOMac
地址一直在变- 目的
IP
是一种长远目标,MAC
是下一阶段目标,目的IP是路径选择的重要依据,MAC
地址是局域网转发的重要依据 - 目的
IP
就是告诉你我的终点要去哪,MAC
地址就是告诉你,我下一站要去哪 IP
网络层存在的意义:提供网络虚拟层,让世界的所有网络都是IP
网络,屏蔽最底层网络的差异
MAC地址和IP地址
既然有了IP地址,为什么还需要MAC地址?
1、对于网络中的一些设备,路由器或者是PC及而言,IP地址的设计是出于拓扑设计出来的,只要在不重复IP地址的情况下,它是可以随意更改的;而MAC地址是根据生产厂商烧录好的,它一般不能改动的,一般来说,当一台PC机的网卡坏了之后,更换了网卡之后MAC地址就会变了。
2、在前面的介绍里面,它们最明显的区别就是长度不同,IP地址的长度为32位,而MAC地址为48位。
3、它们的寻址协议层不同。IP地址应用于OSI模型的网络层,而MAC地址应用在OSI模型的数据链路层。 数据链路层协议可以使数据从一个节点传递到相同链路的另一个节点上(通过MAC地址),而网络层协议使数据可以从一个网络传递到另一个网络上(ARP根据目的IP地址,找到中间节点的MAC地址,通过中间节点传送,从而最终到达目的网络)。
4、分配依据不同。IP地址的分配是基于我们自身定义的网络拓扑,MAC地址的分配是基于制造商。一个是主观的,而另一种是可观的。
5、最重要的区别在于,IP地址划分时基于地理区域,换了不同地方,即便是同一台硬件设备,IP地址一定不一样,可以理解为和地理位置有关;而MAC地址不依赖于地理区域,换了不同地方,只要还是同一台硬件设备,MAC地址就不会变,它只和硬件设备有关。
Socket编程
数据交给主机还不是网络通信的最终目的,让进程拿到数据,才是最终目的,我们启动的上层应用,实际上都是进程,进程拿到了数据,也就相当于人拿到了数据。
因为一个主机中会有很多个进程,所以我们需要一个东西来标识进程在系统中的唯一性
端口号
- 端口号是一个2字节,16位的整数
- 端口号用来标识一个进程,告诉
OS
,当前的数据要交给哪一个进程处理 - 所以
IP地址 + 端口号
基本就能标识网络中的某一台主机上的某一个进程 - 一个端口只能被一个进程占用,但是一个进程可以绑定多个端口
端口划分:
- 0 -1023: 知名端口号
HTTP
,FTP
,SSH
等这些广为使用的应用层协议,他们的端口号都是固定的 - 1024 - 65535:操作系统动态分配的端口,客户端程序的端口就是由OS从这个范围分配的
有一个问题,为什么不在网络上直接用pid
来标识进程的唯一性呢?
因为设计者不想让系统和网络强耦合,就像你已经有了能在社会上唯一标识的身份证,学校还是要给你分配一个学号
理解Socket
- 综上,
IP
地址用来标识互联网中唯一的一台主机,port
用来标识该主机上唯一的一个网络进程 IP+Port
就能表示互联网中唯一的一个进程- 所以,通信的时候,本质是两个互联网进程代表人来进行通信,
{srcIp,srcPort,dstIp,dstPort}
这样的 4 元组就能标识互联网中唯二的两个进程 - 所以,网络通信的本质,也是进程间通信
- 我们把
ip + port
叫做套接字socket
认识传输层协议
TCP:传输层协议,有连接,可靠传输,面向字节流
UDP:传输层协议,无连接,不可靠传输,面向数据报
网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分。那么如何定义网络数据流的地址呢?
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
- 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
- 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
TCP/IP
协议规定,网络数据流应采用大端字节序,即低地址高字节.- 不管这台主机是大端机还是小端机,都会按照这个
TCP/IP
规定的网络字节序来发送/接收数据; - 如果当前发送主机是小端,就需要先将数据转成大端; 否则就忽略,直接发送即可;
CSDN有关整数和浮点数在内存中存储
为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
- 这些函数名很好记,h表示
host
,n 表示network
,l 表示 32 位长整数,s 表示 16 位短整数 - 例如
htonl
表示将 32 位的长整数从主机字节序转换为网络字节序,例如将IP
地址转换后准备发送 - 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回
- 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回
Socket编程接口
// 创建 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)
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
结构体,就可以根据地址类型字段确定结构体中的内容socket API
可以都用struct sockaddr *
类型表示, 在使用的时候需要强制转化成sockaddr_in
,这样的好处是程序的通用性, 可以接收IPv4
,IPv6
,以及UNIX Domain Socket
各种类型的sockaddr
结构体指针做为参数
// Linux 2.6.18 内核typedef unsigned short sa_family_t;
struct sockaddr {sa_family_t sa_family; /* address family, AF_xxx */char sa_data[14]; /* 14 bytes of protocol address */
};/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {sa_family_t sin_family; /* Address family */unsigned short int sin_port; /* Port number */struct in_addr sin_addr; /* Internet address *//* Pad to size of `struct sockaddr'. */unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
};// 虽然 socket api 的接口是 sockaddr, 但是我们真正在基于 IPv4 编程时,
// 使用的数据结构是 sockaddr_in; 这个结构里主要有三部分信息: 地址类型,端口号,IP地址/* Internet address. */
struct in_addr {__u32 s_addr;
};
// in_addr 用来表示一个 IPv4 的 IP 地址. 其实就是一个 32 位的整数;