一、 初识协议
- "协议" 是⼀种约定
- 打电话约定电话铃响的次数的约定
计算机之间的传输媒介是光信号和电信号;通过 "频率" 和 "强弱" 来表示 0 和 1 这样的信息;要想传递各种不同的信息;就需要约定好双方的数据格式
思考:只要通信的两台主机,约定好协议就可以了么?
- 定好协议,但是你用频率表示01,我用强弱表⽰01,就好比我用中国话,你用葡萄牙语⼀样,虽然大家可能遵守的⼀套通信规则,但是语言不同,即是订好了基本的协议,也是无法正常通信的
所以,完善的协议,需要更多更细致的规定,并让参与的⼈都要遵守
- 计算机生产厂商有很多
- 计算机操作系统,也有很多
- 计算机网络硬件设备,还是有很多
- 如何让这些不同厂商之间生产的计算机能够相互顺畅的通信?就需要有人站出来,约定⼀个共同的标准,大家都来遵守,这就是⽹络协议
二、 协议分层
- 协议本质也是软件,在设计上为了更好的进⾏模块化,解耦合,也是被设计成为层状结构的
(1) 软件分层的好处
- 在这个例子中,我们的 "协议" 只有两层:语言层、通信设备层
- 但是实际的网络通信协议,设计的会更加复杂,需要分更多的层
- 但是通过上面的简单例子,我们是能理解,分层可以实现解耦合,让软件维护的成本更低
(2) OSL七层模型
- OSI(Open System Interconnection,开放系统互连)七层网络模型称为开放式系统互联参考模型,是⼀个逻辑上的定义和规范
- 把网络从逻辑上分为了7层,每⼀层都有相关、相对应的物理设备,比如路由器,交换机
- OSI 七层模型是⼀种框架性的设计方法,其最主要的功能使就是帮助不同类型的主机实现数据传输
- 它的最大优点是将服务、接口和协议这三个概念明确地区分开来,概念清楚,理论也比较完整,通过七个层次化的结构模型使不同的系统不同的⽹络之间实现可靠的通讯
- 但是,它既复杂又不实用;所以我们按照TCP / IP四层模型来讲解
- 其实在网络角度,OSI定的协议7层模型其实非常完善,但是在实际操作的过程中,会话层、表示层是不可能接入到操作系统中的,所以在工程实践中,最终落地的是5层协议
- 但是要理解上面的话,需要我们学习完⽹络才可以理解,这里就知道就可以
(3) TCP/IP五层(或四层)模型
- TCP / IP是⼀组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇
- TCP / IP通讯协议采用了5层的层级结构,每⼀层都呼叫它的下⼀层所提供的网络来完成自己的需求
- 物理层:负责光/电信号的传递方式;⽐如现在以太网通通用的⽹线(双绞线)、早期以太网采用的的同 、轴电缆(现在主要用于有线电视)、光纤,现在的wifi无线网使用电磁波等都属于物理层的概念;物理层的能力决定了最大传输速率、传输距离、抗干扰性等;集线器(Hub)工作在物理层
- 数据链路层:负责设备之间的数据帧的传送和识别;例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作;有以太网、令牌环网,无线LAN等标准;交换机(Switch)工作在数据链路层
- ⽹络层:负责地址管理和路由选择;例如在IP协议中,通过IP地址来标识⼀台主机,并通过路由表的方式规划出两台主机之间的数据传输的线路(路由);路由器(Router)工作在网路层
- 传输层:负责两台主机之间的数据传输;如传输控制协议 (TCP),能够确保数据可靠的从源主机发送到目标主机
- 应用层:负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等;我们的⽹络编程主要就是针对应用层
物理层我们考虑的⽐较少,我们只考虑软件相关的内容;因此很多时候我们直接称为TCP / IP四层模型
- 对于⼀台主机,它的操作系统内核实现了从传输层到物理层的内容
- 对于⼀台路由器,它实现了从网络层到物理层
- 对于⼀台交换机,它实现了从数据链路层到物理层
- 对于集线器,它只实现了物理层
但是并不绝对;很多交换机也实现了网络层的转发;很多路由器也实现了部分传输层的内容(比如端口转发)
三、 再识协议
(1) 为什么要有TCP / IP协议?
- 首先,即便是单机,你的计算机内部,其实都是存在协议的,比如:其他设备和内存通信,会有内存协议;其他设备和磁盘通信,会有磁盘相关的协议,比如:SATA,IDE,SCSI等;只不过我们感 知不到罢了;而且这些协议都在本地主机各自的硬件中,通信的成本、问题比较少
- 其次,网络通信最大的特点就是主机之间变远了;任何通信特征的变化,⼀定会带来新的问题,有问题就得解决问题,所以需要新的协议
- 所以,为什么要有TCP/IP协议?本质就是通信主机距离变远了
(2) 什么是TCP / IP协议?
- TCP / IP协议的本质是⼀种解决⽅案
- TCP / IP协议能分层,前提是因为问题们本⾝能分层
(3) TCP/IP协议与操作系统的关系(宏观上,怎么实现的)
所以究竟什么是协议?
- 截止到目前,我们还没接触过任何协议,但是如何朴素的理解协议,我们已经可以试试了
- OS源代码⼀般都是用C / C++语言写的
📍 问题:主机B能识别data,并且准确提取a=10,b=20,c=30吗?
回答:肯定是可以的!因为双方都有同样的结构体类型 struct protocol;也就是说,用同样的代码实现协议,用同样的自定义数据类型,天然就具有"共识",能够识别对方发来的数据,这就是约定啊
关于协议的朴素理解:所谓协议,就是通信双方都认识的结构化的数据类型
因为协议栈示分层的,所以,每层都有双方都有协议,同层之间,互相可以认识对方的协议
四、 网络传输基本流程
(1) 局域网络传输流程图
局域网(以太网为例)通信原理
- 首先回答,两台主机在同⼀个局域网,是否能够直接通信?
- 每台主机在局域⽹上,要有唯⼀的标识来保证主机的唯⼀性:mac地址
(2) 认识MAC地址
- MAC地址用来识别数据链路层中相连的节点
- 长度为 48 比特位,即 6 个字节;⼀般用 16 进制数字加上冒号的形式来表示
- 在网卡出厂时就确定了,不能修改;mac地址通常是唯⼀的(虚拟机中的mac地址不是真实的mac地址,可能会冲突;也有些网卡支持用户配置mac地址)
- windows>ipconfig/all
后⾯我们详细谈论数据链路层的时候,会谈 mac 帧协议,此处我们做⼀个了解即可
- 以太网中,任何时刻,只允许一台机器向网络中发送数据
- 如果有多台同时发送,会发生数据干扰,我们称之为数据碰撞
- 所有发送数据的主机要进行碰撞检测和碰撞避免
- 没有交换机的情况下,⼀个以太网就是⼀个碰撞域
- 局域网通信的过程中,主机对收到的报文确认是否是发给自己的,是通过目标mac地址判定
- 这里可以试着从系统角度来理解局域⽹通信原理
初步明白了局域网通信原理,再来看同⼀个网段内的两台主机进行发送消息的过程
而其中每层都有协议,所以当我进行进行上述传输流程的时候,要进行封装和解包
下面我们明确⼀下概念
- 报头部分,就是对应协议层的结构体字段,我们⼀般叫做报头
- 除了报头,剩下的叫做有效载荷
- 故,报文 = 报头 + 有效载荷
然后,我们在明确⼀下不同层的完整报⽂的叫法
- 不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在⽹络层叫做数据报 (datagram),在链路层叫做帧(frame)
- 应用层数据通过协议栈发到网络上时,每层协议都要加上⼀个数据首部(header),称为封装 (Encapsulation)
- 首部信息中包含了⼀些类似于首部有多长,载荷(payload)有多长,上层协议是什么等信息
- 数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,根据⾸部中的"上层协议字段" 将数据交给对应的上层协议处理
在网络传输的过程中,数据不是直接发送给对方主机的,而是先要自定向下将数据交付给下层协议, 最后由底层发送,然后由对方主机的底层来进行接受,在自底向上进行向上交付,下面是⼀张示意图
(3) 数据包封装和分用
下图为数据封装的过程
下图为数据分用的过程
📍 从今天开始,我们学习任何协议,都要先宏观上建⽴这样的认识:
- 要学习的协议,是如何做到解包的?只有明确了解包,封包也就能理解
- 要学习的协议,是如何做到将⾃⼰的有效载荷,交付给上层协议的?
(4) 跨⽹络传输流程图
⽹络中的地址管理 - 认识IP地址
IP 协议有两个版本,IPv4 和 IPv6;我们整个的课程,凡是提到IP协议,没有特殊说明的,默认都是指 IPv4
- IP 地址是在 IP 协议中,⽤来标识⽹络中不同主机的地址
- 对于 IPv4 来说,IP 地址是⼀个 4 字节,32 位的整数
- 我们通常也使用 "点分⼗进制" 的字符串表示 IP 地址,例如 192.168.0.1;用点分割的每⼀个数字表示⼀个字节,范围是 0 - 255
跨⽹段的主机的数据传输;数据从⼀台计算机到另⼀台计算机传输过程中要经过⼀个或多个路由器
⾸先理解⼀下IP地址的意义
- 为什么要去目标主机,先要走路由器?(只要网段不同就一定要路由器转发,MAC地址只在局域网内有效)
- 目的IP的意义
然后结合封装与解包,体现路由器解包和重新封装的特点
对⽐比P地址和Mac地址的区别
- IP地址在整个路由过程中,⼀直不变(目前,我们只能这样说明,后面再修正)
- Mac地址⼀直在变
- 目的IP是⼀种长远目标,Mac是下⼀阶段目标,目的IP是路径选择的重要依据,mac地址是局域网转发的重要依据
提炼IP网络的意义和网络通信的宏观流程
- IP网络层存在的意义:提供网络虚拟层,让世界的所有网络都是 IP 网络,屏蔽最底层网络的差异
Socket编程预备
五、 理解源IP地址和目的IP地址
- IP 在⽹络中,用来标识主机的唯⼀性
- 注意:后面我们会讲 IP 的分类,后面会详细阐述 IP 的特点
但是这里要思考⼀个问题:数据传输到主机是目的吗?不是的;因为数据是给人用的;比如:聊天是人在聊天,下载是人在下载,浏览网页是人在浏览?
但是⼈是怎么看到聊天信息的呢?怎么执行下载任务呢?怎么浏览网页信息呢?通过启动的 qq,迅雷,浏览器
⽽启动的 qq,迅雷,浏览器都是进程。换句话说,进程是⼈在系统中的代表,只要把数据给进程,⼈就相当于就拿到了数据
所以:数据传输到主机不是目的,而是手段;到达主机内部,在交给主机内的进程,才是目的
但是系统中,同时会存在非常多的进程,当数据到达目标主机之后,怎么转发给目标进程?这就要在网络的背景下,在系统中,标识主机的唯⼀性
六、 认识端口号
端口号( port )是传输层协议的内容
- 端口号是⼀个 2 字节 16 位的整数
- 端口号用来标识⼀个进程,告诉操作系统,当前的这个数据要交给哪⼀个进程来处理
- IP地址 + 端口号能够标识网络上的某⼀台主机的某⼀个进程
- ⼀个端口号只能被⼀个进程占用
(1) 端口号范围划分
- 0 - 1023:知名端口号,HTTP,FTP,SSH 等这些广为使用的应用层协议,他们的端口号都是固定的
- 1024 - 65535:操作系统动态分配的端口号;客户端程序的端口号,就是由操作系统从这个范围分配的
(2) 理解 "端口号" 和 "进程ID"
我们之前在学习系统编程的时候,学习了 pid 表示唯⼀个进程;此处我们的端口号也是唯⼀表示⼀个进程;那么这两者之间是怎样的关系?
另外,⼀个进程可以绑定多个端口号;但是⼀个端口号不能被多个进程绑定
- 进程 PID 属于系统概念,技术上也具有唯⼀性,确实可以用来标识唯⼀的⼀个进程,但是这样做,会让系统进程管理和⽹络强耦合,实际设计的时候,并没有选择这样做
(3) 理解源端口号和目的端口号
传输层协议( TCP 和 UDP )的数据段中有两个端⼝号,分别叫做源端⼝号和⽬的端⼝号;就是在描述 "数据是谁发的,要发给谁"
(4) 理解socket
- 综上, IP 地址用来标识互联网中唯⼀的⼀台主机, port用来标识该主机上唯⼀的⼀个网络进程
- IP+Port 就能表示互联网中唯⼀的⼀个进程
- 所以,通信的时候,本质是两个互联网进程代表人来进行通信,{srcIp,srcPort,dstIp,dstPort} 这样的4元组就能标识互联、网中唯⼆的两个进程
- 所以,网络通信的本质,也是进程间通信
- 我们把 ip+port 叫做套接字 socket
七、 传输层的典型代表
- 如果我们了解了系统,也了解了网络协议栈,我们就会清楚,传输层是属于内核的,那么我们要通 过⽹络协议栈进行通信,必定调用的是传输层提供的系统调用,来进行的⽹络通信
(1) 认识TCP协议
此处我们先对 TCP (Transmission Control Protocol 传输控制协议) 有⼀个直观的认识;后面我们再详细讨论TCP的⼀些细节问题
- 传输层协议
- 有连接
- 可靠传输
- 面向字节流
(2) 认识UDP协议
此处我们也是对 UDP ( User Datagram Protocol 用户数据报协议) 有⼀个直观的认识;后面再详细讨论
- 传输层协议
- 无连接
- 不可靠传输
- 面向数据报
八、 网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分;那么如何定义网络数据流的地址呢?
- 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出
- 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到⾼的顺序保存
- 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址
- TCP / IP协议规定,网络数据流应采用大端字节序,即低地址高字节
- 不管这台主机是大端机还是小端机,都会按照这个TCP / IP规定的网络字节序来发送 / 接收数据
- 如果当前发送主机是小端,就需要先将数据转成大端;否则就忽略,直接发送即可
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运⾏,可以调用以下库函数做网络字节序和主机字节序的转换
- 这些函数名很好记,h表示host,n表示network,l表示 32 位长整数,s表示 16 位短整 数
- 例如 htonl 表示将 32 位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送
- 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回
- 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回
📍 ⽹络规定:所有发送到⽹络上的数据,都必须是⼤端的!
九、 socket编程接口
(1) socket常见API
cpp// 创建 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);(2) sockaddr结构
socketAPI是⼀层抽象的⽹络编程接口,适用于各种底层⽹络协议,如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结构体,就可以根据地址类型字段确定结构体中的内容
- socketAPI可以都用 struct sockaddr* 类型表示,在使用的时候需要强制转化成sockaddr_in;这样的好处是程序的通用性,可以接收IPv4;IPv6,以及UNIX Domain Socket 各种类型的sockaddr结构体指针做为参数
sockaddr 结构
sockaddr_in 结构
虽然socket api的接口是sockaddr,但是我们真正在基于IPv4编程时,使用的数据结构是sockaddr_in;这个结构里主要有三部分信息:地址类型,端口号,IP地址
in_addr 结构
in_addr 用来表示⼀个IPv4的IP地址;其实就是⼀个32位的整数
十、 补充
- 协议是一种约定
- 软件协议------>协议分层------>软件分层------>Done(层状结构)
- 任何问题都可以加上一层软件层来解决问题
- 协议的本质是软件,在设计上为了更好的进行模块化,解耦合,也是被设计成了层状结构(使维护成本更低)
- 任何通信特征的变化,一定会带来新的问题
- 协议和OS是用C+汇编语言写的(协议栈的一部分也是被设计到内核中的,协议栈本身也是C语言写的)
- 协议的本质是结构体,协议栈相同,本质就是实现的标准相同
- 网络传输的基本流程
- mac地址是来保证主机唯一性的唯一标识(不能被修改)
- 以太网中,任何时刻,只允许一台机器向网络中发送数据(原子的),意思就是以太网是共享资源 / 临界资源
- 如果有多台同时发送,会发生数据干扰,称为数据碰撞
- 所有发送数据的主机要进行碰撞检测和碰撞避免
- 如若没有交换机的情况下,一个以太网就是一个碰撞域
- 以太网和局域网的关系
- 以太网是实现局域网的一种主流技术标准,局域网是网络的地域范围分类
- 局域网:按地理范围定义的网络类型,不规定具体实现技术
- 以太网:按技术标准定义的通信规范,规定了局域网的接口、传输介质、数据帧格式、访问控制等,是实现局域网的技术手段
- 局域网通信,就是居于碰撞检测和碰撞避免不断重试的过程
- 封装和解包的过程,就是一次入栈和出栈的过程
- 报文=报头+有效载荷
- 报头是结构体变量,封装报头的本质:其实就是在报文头部,拷贝结构体变量(缓冲区)
- IP地址 VS MAC地址
- IP地址在整个路由的过程中,一直不变(从哪里来,到哪里去)
- Mac地址一直在变(上一站哪来,下一站哪去)
- 目的IP是一种长远目标,Mac地址是下一阶段目标,目的IP是路径选择的重要依据,mac地址是局域网转发的重要依据
- IP网络存在的意义:提供网络虚拟层,让世界所有的网络都是IP网络,屏蔽最底层网络的差异,路由器是实现IP通信的底层最重要的硬件
- 网络通信的本质:是进程间通信
- 端口号的核心作用:是在网络传输中给设备上的每个应用分配一个唯一的"门牌号",解决了同一台设备上多个应用同时收发数据不混乱的问题(一个总机收到请求后,通过端口转接到不哦她那个部门)
- 问:pid不就可以标识进程的唯一性么?为什么还要端口号?
答:pid属于系统概念;这是一种解耦合,而且pid是每一个进程都要有,但是不是每一个进程都需要通信
源IP地址和目的IP地址------>保证主机之间进行通信
- 通过端口号进行转发给指定进程,换句话说,我们的未来写代码的时候进行就一定要和指定的Port进行关联
- 数据报文到达目标主机之后,然后继续交付给对应的进程;IP找主机,端口找进程(定位到软件)







所以究竟什么是协议?



















