正如标题所写。这篇文章致力于网络协议的初级扫盲、方便应对日常甚至面试中的尬聊、也是为了对刚补完的网络协议做个归纳。
目录
- TCP/IP协议族的体系结构
- 四层协议模型
- 每层的作用
- TCP/IP协议整体的工作流程
- 网络层
- 传输层
- 应用层
- 最后:网络协议到底有没有用?
TCP/IP协议族的体系结构
-
四层协议模型
虽然与OSI有所不同、但也只是将某些层级合并了而已。
有人说是四层、也有人说是五层(将网络接口层分为数据链路层和物理层
)。但是毕竟是个认为定义的东西、没必要拼个你死我活、理解每一层的作用就好(也有人说ARP以及RARP该归属物理链路层、一样没必要争论
)。
-
每层的作用
尝试性的总结以及类比一下、但是不确保100%吻合、因为现实毕竟和网络上不同(你见过谁家快递员专职住你公司里签单子?)。
- 四层结构(橙色)全部处于主机内部、并且
源主机
和目标主机
甚至路由器
都含有它们。 - 应用层并不代指APP、而是供APP调用(
比如HTTP
)。 - 传输层负责这次传输的具体规则(
重发、拥塞控制)
。 - 网络层只负责传输、其余全部不管。
- 物理链路层实际上就是网卡(
比如以前手机的网卡不能连wifi
)。
-
TCP/IP协议整体的工作流程
原始数据包会经过一层一层的封装(为了让下一层能够识别必须添加特定的包头
)、向下传递。而后在目的地一层一层将数据取出。
网络层
是TCP/IP协议中最重要的一层
-
路由器是如何工作的?--路由协议
-
路由器
负责报文(数据包)的转发以及路径的选择
包括但不限于家用路由器、这里更多的指运营商处的大型路由器。
路由表
路径选择
主要依靠路由表
(也就是通过我可以到达网络的表格)实现。包括静态路由表(网络管理员负责建立、但基本没人用
)以及动态路由表(通过路由协议建立
)。
工作原理
- 如果目的地址存在于路由表中、那么直接转发。
- 如果目的地址不存在于路由表中、那么则发给默认路由。
- 通过网络号而不是整个IP地址进行路由判断
-
路由协议
帮助路由器建立路由表
分为两种算法实现:
距离向量路由算法
要求路由器将自己的路由表发送到临近的节点上
链路状态路由算法
只发送路由表中描述自身链路状态的部分到临近的节点上
二者比较
链路状态算法
相比距离向量算法
在大型网络上更有优势。
由于发送的数据更精简、所以收敛速度更快、网络开销也更小。
路由表到底有多大?
具体要看与自己需要选择转发的网络有多大。
比如、对于家用路由器的路由表自然只要维护自己内部的主机就好、一旦发现数据包不数据自己内部就直接丢给默认端口(当然大型路由器也一样)。
具体可以参阅《网络协议补完计划--路由协议》
————————
-
IP地址是个啥?IP协议
一种无连接的传输协议。只负责数据包的传输、不对任何问题负责。
其实和UDP很像、但是IP数据包的包头中是不含端口号的、只针对主机(IP地址)之间进行传输。
A、B、C、D、E共五类网络地址
常用的网络地址为ABC三类:
A类:0开头、后24位作为主机号、其余作为网络号。
B类:10开头、后16位作为主机号、其余作为网络号。
C类:110开头、后8位作为主机号、其余作为网络号(最常用)
D类:用于UDP多播。
子网掩码
对地址结构的扩展、用于确定网络号与主机号的结构
比如有两个C类地址、他们本属不同的网络。但如果合理使用子网技术、就可以把他们的网络号合并从而形成一个子网。
分片与重组
实际使用中经常会遇到一个IP包传输不完(
比如途中某个物理网络最大传输长度限制
)、需要拆分的情况。
对于大于MTU(最大传输长度
)的数据包、会被拆分然后传输、最后在目的地重组恢复。
分片动作通常由路由器完成、重组由目标主机完成(降低了中间路由器压力)。
需要注意的是一旦任何分片丢失、目的主机都会要求重传所有分片
NAT网络地址转换
一种通过将内部不同
私网IP及端口
与公网端口绑定
、以达到内部所有计算机
通过一个公网IP
进行外界沟通的作用。
我们现在基本都是使用了这个技术、如果你有两台主机就会发现他们的公网IP其实是相同的。
这个技术在很大程度上也缓解了IP地址不足的问题(虽然不能根治)。
具体可以参阅《网络协议补完计划--IP协议》
————————
-
未来的新型IP地址--IPv6
- 扩展地址
有IPv4的32(46亿个
)位扩展为128位(340万亿个
) - 简化的包头
- 流标记
相同流向的数据包不需要每次进行寻路
具体可以参阅《网络协议补完计划--IPv6》
————————
-
MAC地址有什么作用?--ARP协议
用IP地址映射所对应的MAC地址
在物理层上、并不是通过IP地址来确定通讯目标(有可能是因为网络兴起初期协议很多、IP协议并不占主导
)、而是通过网卡的MAC地址。
IP地址指向最终的主机地址、而MAC地址指向下一跳的目标位置。
工作流程
①当电脑没有网关(采用代理ARP)时:"跨网段访问谁,就问谁的MAC"
②当电脑有网关(采用正常ARP)时:"跨网段访问谁,都问网关的MAC"
③无论哪种ARP,跨网段通信时,发送方请求得到的目标MAC地址都是网关MAC。
与之对应的还有RARP协议(用于网络中某些需要远程启动的无盘工作站获取IP地址
)
具体可以参阅《网络协议补完计划--ARP协议和RARP协议》
————————
-
我们总说ping一下。本质是个啥?--ICMP协议
发现错误的路由器、向数据包的(通过IP数据包的信息获取)源主机地址发送一个ICMP数据包、并且通过ICMP数据包报告出错的原因。
ICMP协议是IP协议的补充、
ICMP与IP协议位于同一个层次
(IP层),但ICMP报文是封装在IP数据包的数据部分
进行传输的。-
总的来看可以分为如图所示的三大 类:差错报告、控制报文和请求应答报文:
大部分都是给源路由器看的(比如网络不可达
/源抑制
等等)
我们日常用到的ping命令
:作用就是我们发送请求报文
、目标服务器返回一个应答报文
以此判断目标主机是否存在
。
具体可以参阅《网络协议补完计划--ICMP协议》
————————
如何动态分配IP地址?--广播与多播
动态主机配置协议(Dynamic Host Configuration Protocol,DHCP),在认定本地子网上有一个DHCP服务器主机或中继主机的前提下,DHCP客户主机向广播地址(通常是255.255.255.255,因为客户主机还不知道自己的IP地址、子网掩码及本子网的受限广播地址)发送自己的请求。
单播
点对点的通讯方式广播(IPv4)
向所有的主机同时通讯多播(组播)
向某些主机同时通讯泛播(IPv6)
向任意一些主机中的某一个发起通讯。可以参照负载均衡来理解、我想知道当前时间、10个服务器有资格响应、但最终只有一个离我最近的服务器完成响应
。
注意这里虽然在网络层所提到的广播多播、也就是通过特定的IP地址实现。例如:
主机位全部为1(xxx.xxx.xxx.255
)则为该网络的广播地址。
但并不妨碍我们在UDP中使用:
比如我们可以监听一个端口、然后向本地广播地址发送UDP数据包
进行本地群组聊天
或者通过单播地址
来点对点聊天
。
TCP不支持广播和多播:具体等说到TCP时再说。
具体可以参阅《网络协议补完计划--广播与多播》
传输层
在运行在不同主机上的进程提供逻辑通讯的功能、使彼此感觉直接相连
-
套接字(socket)
总是成对出现、是应用层到传输层的门户。
套接字本质上就是操作系统为传输层公开的API、帮助我们组装传输层数据包并交给IP层发送。
套接字(socket
)并不单指TCP(长连接
)、TCP/IP协议族中包括三种套接字:
- 流式套接字--TCP协议专属
- 数据报套接字--UDP协议专属
- 原始套接字--可以直接访问IP层
我们可以举个C语言socket编程的例子:
//创建一个TCP的scoket
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//创建一个UDP的scoket
SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
——————
-
UDP协议--(用户数据报协议(User Datagram Protocol))
不可靠的无连接的数据包传输服务
只负责发送、不保证安全性(确认到达)以及顺序。这点其实和IP协议的本质一样。
所以、UDP可以在不建立连接的情况下随意向主机的某个端口发送数据(但源主机并不知道是否发送成功、甚至目标主机都不知道是谁发来的数据
)。
-
TCP协议--(传输控制协议Transmission Control Protocol))
面向链接的可靠的字节流传输服务
即TCP协议数据包会保证重发、有序还有拥塞控制。确保从发送方发出的数据、按照顺序完整的交付给接收方。
所以、TCP链接需要经历三次握手(双方确认相互可以收发数据
)、四次挥手(双方先后申请断开单向链接并被确认
)
此外TCP是全双工的、数据的发送、接收可以同时双向进行。
————————
-
TCP协议与UDP协议的比较
借用《《知乎》》上的一个很有趣的例子:
亚当和夏娃分别生活在两个山头,山头之间是万丈深渊,亚当采集野果需要分享给夏娃,如果他们之间有一条索道(物理连接),野果可以顺着索道滑到夏娃那一边,那就没有网络协议什么事了。
事实上山头之间没有索道。但是亚当何等聪明,于是他想出了一个方法,假设亚当需要给夏娃10个野果,否则她会饿死。
============================
《《《《《《对于TCP》》》》》》
============================
连接建立
亚当对着夏娃大喊:爱妃,你听得到吗?
夏娃回应:孩他爹,我听得到!
亚当接着喊:那好,我扔果子给你吃,你接到果子就喊一声,一共十个。
运送货物
于是亚当开始扔第一个,夏娃喊收到了一个。
亚当扔第二个,夏娃喊收到两个。
超时重传 ( timeout retransmit)
亚当扔第三个,可是夏娃迟迟没有回音,亚当意识到可能果子落到悬崖了,于是重新扔,夏娃喊收到第三个。
Advertised window size = 0
于是亚当连续扔了第四、五、六个,夏娃急了:孩他爹,慢点扔,臣妾忙不过来了…
Advertised window size > 0
于是亚当坐下休息,爱妃又开始叫了:继续扔吧。
亚当开始扔第七个,夏娃喊收到七个。
…
关闭连接
终于亚当扔完了,亚当喊:爱妃,果子扔完了,寡人去忙别的了。
夏娃回复:好的,我也休息一下,再见。
亚当:再见
以上的过程类似TCP连接的过程,TCP是一个虚拟连接
============================
《《《《《《对于UDP》》》》》》
============================
亚当和夏娃吵架了,任凭亚当如何大声喊,夏娃躲在树林后生闷气,一声不响,亚当害怕夏娃饿死,于是
开始自说自话朝着夏娃的山头扔玉米棒子:
一个、两个、三个…
一共扔了十个,但最终扔到对方山头到底有几个,亚当没有底,也许有的玉米棒子落到悬崖了,但是这个效率高啊,可以连续扔,以前扔10个果子需要一分钟,现在只需要20秒。
亚当扔果子、扔玉米都有可能扔到悬崖下,但是扔果子为何可以确保对方收到十个?那是因为夏娃收到一个果子,然后喊收到了,如果没有收到,亚当就重新扔,直到夏娃说收到了。而扔玉米棒子对方没有确认,所以对于丢弃的情况无法知道,也无法重新扔。
面向连接的传输服务
-
TCP以连接作为协议数据的最终目标
TCP协议的端口是可以复用
对于TCP协议,要成功建立一个新的链接,需要保证新链接四个要素组合体的唯一性:客户端的IP、客户端的port、服务器端的IP、服务器端的port。也就是说,服务器端的同一个IP和port,可以和同一个客户端的多个不同端口成功建立多个TCP链接(与多个不同的客户端当然也可以),只要保证【Server IP + Server Port + Client IP + Client Port】这个组合唯一不重复即可。
-
UDP以端口作为协议数据的最终目标
UDP协议的端口不可复用
对于UDP协议、是以监听端口作为操作的。而且在协议中、源端口和源IP地址都是可选项。哪怕不填(只制定了目的端口和目的地址)也可以成功发送。
-
TCP协议需要先建立连接、然后才能发送/接收数据
并且需要对很多细节进行协商(最大数据长度、窗口大小、初始序列号等) - UDP协议直接发送/接收数据
可靠的传输服务
-
TCP协议提供的是可靠的传输服务
以序列号保证有序、以重发机制保证成功发送。 -
UDP协议提供的是不可靠的传输服务
可能会丢失、失序、重复等。
面向字节流的传输服务
-
TCP协议是以字节为单位流式传输数据
TCP的传输是无边界的 -
UDP协议是以数据块传输数据
UDP的传输是有边界的
——————————
-
TCP应用于UDP应用
1. TCP
以可靠传输为基准:FTP、Telnet、http、自建通道。
2. UDP
对时效性为基准:实时应用、多播式应用。
使用UDP时应该注意一下几点:
1. 应用程序必须自己来保证可靠性
应用程序必须有自己的重发机制、数据失序处理、流量控制等。
2. 应用程序必须自己来处理大块数据
发送方对大块数据进行分割、接收方还要进行重组
QQ就是采用《可靠的UDP》+TCP来实现。其中UDP主要负责通讯、TCP负责最低限度状态的维持。
影响TCP和UDP选择的最大原因
很多游戏选择UDP而非TCP、并不是因为来回的确认包会浪费资源或者拖慢网速(因为可靠的UDP也需要确认包
)、更不是三次握手。
更重要的原因是TCP的阻塞窗口机制会《在发生阻塞时自动减少数据段的发送》、一旦网络发生波动、TCP的这个自宫机制会让应用程序的延迟更高。而在网络恢复后、TCP的慢启动机制也会延缓恢复的时间。
关于TCP和UDP具体可以参阅《网络协议补完计划--TCP协议》、《网络协议补完计划--UDP协议》
应用层
-
HTTP
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应、在
请求结束后(HTTP1.0)恰当的时候(keep-alive)、会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
实际上HTTP就是对于TCP的二次封装、使得我们只需要传入很少的参数便能使用TCP链接以《请求--应答》的方式进行通讯。默认端口为80.
HTTP1.0:
- 无连接
每次通讯结束会自动释放链接 - 无状态
服务器无法记录用户以前的动作
HTTP1.1:
- 新头部字段
主机名、身份认证、状态管理和Cache缓存等 - Connection-Keep-Alive
保持长连接(默认开启--但是服务器通常会偷偷的释放掉连接以节省资源
) - 支持在一次连接中同时发出多个请求
但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容。这也叫做《队首阻塞》。 - 断点续传
HTTP2.0:
多路复用
基于二进制分帧层,HTTP 2.0可以在共享TCP连接的基础上,同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义,交错发送出去,最后在另一端根据流ID和首部将它们重新组合起来
。头部压缩
更小的头部体积、传输更快
HTTP状态码
1xx(临时响应
)、2xx(请求成功
)、3xx(重定向
)、4xx(客户机错误
)、5xx(服务器错误
)。
Cookie
服务器通过响应头发送一个用于识别身份的cookie字符串
让《客户端保存》、客户端在之后的请求中将该cookie放在请求头中发送
。
需要注意的是cookie是不能跨域的、而且https和http共用同一个。
Session
与cookie客户端保存不同、session是由《服务器生成并保存》每个连接者的身份信息(session)。而这个身份信息与客户端的cookie绑定、所以也有人说session是基于cookie实现
的。
具体可以参阅《网络协议补完计划--HTTP协议》
——————————
HTTPS
负责《帮助服务器和客户端在安全的环境下协商出一个秘钥》以《进行加密传输》。
主要用到了三种技术:
- 使用
数字证书以及数字签名
技术实现服务器公钥认证 - 使用公钥实现
在非对称加密
状态下协商通信秘钥 - 使用通信秘钥实现
对称加密
状态下的安全通信
具体可以参阅《网络协议补完计划--HTTPS》
最后:网络协议到底有没有用?
这个问题没有定论。因为对于绝大部分人而言、我们只需要了解HTTP、甚至连了解都不用只需要会调用API就够了。
所以具体有没有用、要看工作中有没有遇到什么问题。
当项目足够大、或许就用得上了。
以美团移动网络的架构作为例举
这个架构图基本上已经涵盖了目前所有的通讯方式、并加以合理利用
TCP子通道:
专用的TCP长连接通道。所有客户端的HTTP请求默认都会被加工成二进制数据包放在专用的TCP通道发送给代理服务器。
UDP子通道:
作为TCP的降级方案使用、如果TCP不同则尝试使用UDP通道通讯。
HTTP子通道:
当TCP与UDP均不可用、则直接使用HTTP对业务服务器进行公网请求。
HTTP通道:
上传和下载大数据包的请求如果放在长连上进行都有可能导致长连通道的拥堵,因此我们将CDN访问、文件上传和频繁的日志上报等放在公网利用HTTP短连进行请求,同时也减轻代理长连服务器的负担。
WNS通道:
出于灾备用TCP通道