TCP/IP协议

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

作者~小明学编程  

文章专栏JavaEE

格言热爱编程的终将被编程所厚爱。
在这里插入图片描述

目录

应用层

XML

json

​编辑

protobuffer

传输层

UDP的数据报文格式

TCP报文格式

TCP的可靠传输

确认应答安全机制

超时重传安全机制

连接管理机制安全机制

三次握手

四次挥手

滑动窗口效率机制

流量控制安全机制

拥塞控制安全机制

 延迟应答效率机制

捎带应答效率机制

面向字节流

TCP异常处理

网络层

IP协议

地址管理 

 子网掩码

 特殊的IP地址

IP地址不够用问题

路由管理

数据链路层

特殊协议


应用层

应用层是我们最为重要的一层在应用层我们需要自己去设计一个合适的协议来供前后端的交互使用其中比较知名的应用层协议就是HTTP协议。

下面我们介绍几种常见的应用层模板

XML

1.可读性好但是运行效率不高属于老的数据格式了。虽然也在用但是用的越来越少了。
2.特点由标签构成 <标签名>内容</标签名> 标签名就是 key标签值就是 value 通过标签就更好的提升了可读性。
3.虽然提高了可读性但是又引入了太多的辅助信息标签名之类的 就导致占用了更高的 网络带宽。
4.所以 xml 就很少作为 应用层协议的 模板了更多的是用来做一些配置文件。

json

1.可读性好但是运行效率不高。当下最流行的一种设计 应用层协议 的数据格式通过 大括号 构成了键值对格式。
2.一个 大括号 中有很多键值对键值对之间使用 逗号 分割键 和 值 之间使用 冒号 分割。
3.要求 键 必须是字符串类型的 值允许有好多种数字字符串布尔数组另一个 json。
4.json 中表示字符串单引号和双引号都可以最后一个键值对后面可以有逗号也可以没有标准要求是没有的但是一般的 json 解释器都不会在意。
5.json 要求 key 一定是字符串因此 key 这里的引号可以忽略除非 key 中包含了一些特殊符号比如像 空格-就不能省略了。

json 和 xml 对比

相比于 xml 来说json 也能保证可读性同时又没有那么繁琐占用的带宽小.
json 虽然传输效率比 xml 高但是然然要多传递一些冗余信息就是 key 的名字尤其是数组的时候更明显。当表示数组的时候就会有很多 key 重复出现也就占用了带宽。出问题的请求和响应一目了然。

protobuffer

1.运行效率高但是可读性不高。
2.是一种 二进制格式 的数据在 protobuffer 的数据中不再包含 key 的名字。而是通过顺序以及一些特殊符号来区分每个字段的含义。同时再通过一个 LDL 文件。来描述这个数据格式每个部分是啥意思。
3.LDL 只是起到一个辅助开发的作用并不会真正的进行传输传输的只是二进制的纯粹的数据。
 

传输层

UDP的数据报文格式

这是我们的UDP的数据报的报文格式在进入到传输层的时候我们会对其加上UDP的报头这个报头一共占8个字节这8个字节分别是分给我们的源端口也就是我们操作系统给我们的客户端分配的一个端口号目的端口也就是我们服务端的端口号报文长度就是我们想要发送内容所占的字节长度校验和就是对我们所发送的数据进行一个校验。

TCP报文格式

 

TCP相比DCP要更加的复杂同时TCP的应用也更加的广泛下面就简单的给大家介绍一下这些格式的含义。

 1.首先是16位的源端口号和16位的目的端口号也就是我们客户端和服务端的两个端口号16位也就是两个字节和DCP一样。

2.4位首部长度是来描述我们报头的大小的其单位是4个字节因为我们报头的大小不是固定的因为选项的存在选项可有可无可以有多个所以我们的大小不固定我们在计算报头长度的时候就要根据4位首部长度来计算4位所能表示的最大值为15其大小也就是15*4=60字节。

3.保留位是用来未雨绸缪的现在暂时还用不到但是未来用不用的到升级用不用的到那就不一定了。

TCP的可靠传输

TCP的四大特点可靠传输有连接字节流双全工其中最重要的就是我们的可靠传输可靠传输也就是我们的发送端知道我们的接收端有没有接收到并且数据能按照我们想要的方式传送到位那么这一功能是如何实现的呢

 这是AB二人在互相发消息因为传输的问题就导致了B的回复发生了错乱A先问的身高结果体重的消息先达到了这就是典型的不可靠传输当然我们上述案例是从宏观上来看的从微观上来看的话那就是你怎么保证你发的是你多高而不是高多你。

TCP的可靠传输基于两点来解决问题1.确认应答  2.超时重连

确认应答安全机制

确认应答就是来解决前面的乱序问题的想要解决这个问题的话我们可以采用对数据进行一个排序的方式。

TCP将每个字节的数据都进行了编号即为序列号每一个ACK都带有对应的确认序列号意思是告诉发送者我已经收到了哪些数据下一次你从哪里开始发。

这样就解决了我们数据发送混乱的问题了。

超时重传安全机制


 非一般的情况下总是会有意外的导致我们的数据不能正常的发送到位就像上述的情况A给B发了一个吃了吗有可能中间会产生丢包的情况我们的B没有接收到消息自然也就不会发送ack了还有一种可能就是B接收到消息了然后发送ack但是ack在发送的时候发生了丢包的情况这样也会导致我们的A接受不到ack也就是A会觉得自己的消息B没有接收到。

对于上述的情况TCP设定了超时重连当发送端发送数据后在指定的一段时间没有收到ack,就会触发重发机制重新打包发送我们的数据但是这又会产生一个问题如果是我们发送的时候丢包没问题重发就行了万一是我们的ack发生了丢包重发岂不是会存在多份数据。

这个问题TCP也帮我们给解决了当我们接收到数据的时候我们的数据是放在操作系统的接受缓存区的如果收到新的数据我们的TCP就会去接受缓存区中去检索有没有这个消息如果有的话就就丢弃如果没有的话就放进去用来保证程序调用 socket API 拿到的这个数据一定是不可重复的。

重传如果失败还会继续尝试也不会无休止的重传连续几次失败的话就认为是网络遇到了严重的情况再怎么重传也可能不行就只能放弃自动断开与 TCP 的连接。重传的时间间隔会逐渐变大。

连接管理机制安全机制

我们知道我们的TCP是有连接的在正常情况下要经历三次握手建立连接四次挥手断开连接。

三次握手

1.客户端先给服务端发送syn想要知道服务端是否能够接收到消息如果服务端接收到了消息那么此时的服务端就知道自己的接受能力没有问题同时客户端的发送能力也没有问题。

2.服务端会发送ack,来告诉客户端我能接收到你的消息并且服务端也要知道客户端能不能知道服务端的消息也会发送一个syn通常情况下这个ack和syn会一起发送。

3.客户端此时接收到反馈也就知道了服务端的接受和发送没有问题同时客户端的发送和接受也没有问题但是我们要服务端知道它的发送和我们客户端的接受没有问题我们将会再次发送一个ack给服务端服务端接收到后就知道双方的接受发送都没有问题了。

第一次握手的时候客户端给服务器发一个 SYN 同步报文段。意思就是客户端要和服务器建立连接。 

 如果 ACK 这一位为 1就表示这个报文是一个确认报文段确认应答报文也就是 ACK 为 1。ACK 这一位为 1 的时候起到一个应答效果用来确认消息是已经送到了的。

三次握手的意义在于去检测将要通信的双方接受和发送的功能是否正常保证后面通信的正常进行如果不正常那就不能连接通信。

四次挥手

断开连接就是四次挥手。三次握手就让客户端和服务器之间建立好了连接。其实在建立好连接之后操作系统内核当中就需要使用一定的数据结构来保存连接的相关的信息保存的信息其实最重要的就是前面说的五元组源IP、源端口、目的IP、目的端口、TCP。有一天连接断开了那么五元组保存的连接信息就没意义了对应的空间就可以释放了。就像攒钱买了手机就和手机联系在了一起。如果有一天又买了新的手机把旧手机卖掉之后就和旧手机的所有联系都断开了。

1.首先我们的其中一个端会发出FIN请求中断连接然后我们的接收端会接收到请求。

2.当我们的接收端接收到请求之后会发送个ack告诉发送端我们接收到了请求。

3.接收端在发送完ack之后同样也会发送FIN请求中断连接。

4.原发送端在接收到请求之后就会相应的也发送ack告诉对放我们也接收到了消息。

重要状态

CLOSE_WAIT

1.这个状态是在挥手两次之后的状态意思为等待关闭这个状态就是在等待代码中调用 socket.close 方法来进行后续的挥手过程。

2.正常情况下一个服务器上面不应该存在大量的 CLOSE_WAIT 如果存在说明大概率是代码 bugclose 没有被执行到。

TIME_WAIT

1.为什么要有这个状态呢一般情况下我们刚开始发送FIN的那一方在发送完并且收到ack之后我们就会觉得没用了可以撤销资源了但是实际的过程中我们最后一个ack可能会发生丢包的情况。

 2.丢包之后我们就会重发这是如果原发送端不见了那么该发送给谁呢所以需要这个等待的状态。

3.TIME_WAIT 持续时间2*MSL MSL表示网络上任意两点之间传输需要的最大时间。这个时间也是系统上可以配置的参数一个典型的设置就是60s经验值。

三次握手和四次挥手的区别

1.发送方不一样三次挥手的发送方一定是客户端但是四次挥手的发送方可能是客户端也可能是服务端。

2.合并问题三次握手是合并了中间了两次但是四次握手一般不能合并因为fin的时机是用户代码负责的而ack是操作系统负责的二者发送时机不一样很难合并。

滑动窗口效率机制

刚才我们讨论了确认应答策略对每一个发送的数据段都要给一个ACK确认应答。收到ACK后再发送下一个数据段这样做有一个比较大的缺点就是性能较差尤其是数据往返的时间较长的时候。
我们在不使用滑动窗口的时候

这个时候我们发送一条消息就要接受一个ack来确认是否时候效率太低了。

使用滑动窗口

在使用了滑动窗口之后我们一次性发送多条消息同时也会接受多哥ack但是每当接受一个ack的时候我们就可以接着发送下一条消息了然后再接受一条就再发一条如果我们接收到下一个是4001这个ack的话那就直接发送四条不用考虑前面的ack有没有到达了因为4001收到以后我们就认为4001之前的数据全部都已经收到了。

滑动窗口让我们把原本一次一次的ack可以放在一起发送极大的节省了时间。

丢包问题

我们一次性发送多条数据那么要是出现丢包问题该怎么解决呢

ack丢了

 ack丢了的话问题不大我们还是会有下一个ack的比如我们的3001这条ack丢了我们就不能保证3001之前的数据有没有安全的发送出去但是5001这条ack安全的发送了出去那就代表5001之前的数据全部收到了。

数据丢失
如果是我们的数据丢失的话就不会这么简单了。

现在我们这条1001-2000的数据没有发送到为中间发生了丢包的情况也接收不到ack,这个时候我们的发送端会发送后面的数据这个时候接收端就发现我们前面的数据还没有接收到接着就察觉到了丢包问题然后就会发送ack告诉数据端下一个是1001然后重复发送直到我们重发并接受到缺失的数据。

流量控制安全机制

接收端处理数据的速度是有限的。如果发送端发的太快导致接收端的缓冲区被打满这个时候如果发送端继续发送就会造成丢包继而引起丢包重传等等一系列连锁反应。
因此TCP支持根据接收端的处理能力来决定发送端的发送速度。这个机制就叫做流量控制Flow
Control。

· 滑动窗口越大传输速率越高不光要考虑发送方还得考虑接收方。
· 发送方发的太快接收方处理不过来就会把新收的包给丢了发送方还得重传。
· 流量控制的关键是能够衡量接收方的速度直接使用接收方接受缓冲区的剩余空间大小来衡量· 当前的处理能力。
· 可以把接收缓冲区理解为一个阻塞队列。B 的应用程序在调用 read 方法的时候就是从接收缓冲区中来取数据。通过 ACK 报文来看缓冲区大小如果接收方反馈的窗口大小是 0那么发送方也会发一个信息用来探测有没有空间。



 可以把其当成一个蓄水池一端负责进水一端负责排水当我们进水过多的时候就予以相应的警告我们的进水量就会相应的减少当水位低的时候也会给出相应的提醒然后进水量增加。

拥塞控制安全机制

拥塞控制也是滑动窗口的延申也是限制滑动窗口的发送速率。控制衡量的是

1.发送方到接收方 整个链路之间的拥堵情况都会影响传输速率。
2.开始的时候以一个比较小的窗口来发送数据如果数据很流畅的到达了那么就加大窗口大小。
3.加大到一定程度之后出现了丢包就意味着链路出现拥堵了然后再减小窗口。
4.通过反复的 增大/减小 最终达到”动态平衡“。通过拥塞窗口来限制滑动窗口的大小。
5.最终滑动窗口的大小 由 拥塞窗口 和 流量控制窗口共同决定由小的一方决定。一旦丢包就立刻让窗口变小降低速度然后继续去试探的增大。
6.如果把窗口一下变得很小就是期望这次传输一定能成功。

总结下来就是说我们在刚开始的时候不知道整个链路是个什么情况会不会导致阻塞拥堵的情况然后我们的滑动窗口的大小就会很小接着窗口大小以指数形式来增长以此试探我们所能接受的最大值一旦超过最大值就会又变成最小值。

值得我们注意的是我们的窗口增长不是一直以指数形式来增长的当达到我们的阈值的时候就改为线性增长了。

当TCP开始启动的时候慢启动阈值等于窗口最大值
在每次超时重发的时候慢启动阈值会变成原来的一半同时拥塞窗口置回1

 延迟应答效率机制

如果接收数据的主机立刻返回ACK应答这时候返回的窗口可能比较小当我们的窗口比较小的时候如果我们的ack很快的应答的话那么我们所的发送的也会很少此时的传输是一个比较阻塞的状态这个时候我们的效率就会比较的低那么我们如果等一会再应答的话此时我们的窗口可能就会相应的大一点此时我们的吞吐量也会相应的大一些提高了效率。

捎带应答效率机制

在延迟应答的基础上我们发现很多情况下客户端服务器在应用层也是 "一发一收" 的。意味着客户端给服务器说了 "How are you"服务器也会给客户端回一个 "Fine, thank you"
那么这个时候ACK就可以搭顺风车和服务器回应的 "Finethank you" 一起回给客户端。

面向字节流

因为我们的TCP传输数据是面向字节流的这样就会导致一个粘包问题

如上所示我们客户端发送的数据在服务端会被接受然后拆分获取里面的主要的数据最后放在缓存区等待socketAPI的拿取但是问题来了应用程序看到了这么一连串的字节数据就不知道从哪个部分开始到哪个部分是一个完整的应用层数据包。

解决明确边界

对于定长的包保证每次都按固定大小读取即可例如上面的Request结构是固定大小
的那么就从缓冲区从头开始按sizeofRequest依次读取即可。
对于变长的包可以在包头的位置约定一个包总长度的字段从而就知道了包的结束位
置。
对于变长的包还可以在包和包之间使用明确的分隔符应用层协议是程序猿自己来定
的只要保证分隔符不和正文冲突即可。

TCP异常处理

进程终止进程终止会释放文件描述符仍然可以发送FIN。和正常关闭没有什么区别要经历四次挥手。

机器关机和进程终止一样。

机器断电/网线断开

1.如果是服务器那边出了问题的话我们服务器会接受不到ack,然后就会进入超时重传当重传几次时候仍然接收不到ack就会尝试重新连接如果重新连接仍然失败那就放弃链接。

2.如果是客户端出了问题服务端会以为客户端一会会继续发送先会等一会等一会还不发送就会发送试探报文如果接收不到ack那就放弃连接。

网络层

IP协议

 IP协议的主要作用就是完成两个方面的工作一个是地址的管理一个是路由的选择。

下面就简单的介绍一下这个写个各个部分是干嘛用的
14位版本号当前的的版本号只有两种一个是4一个是6分别对应的是ipv4和ipv6。

24位首部长度与tcp一样IP的报头也是可变的。

38位服务长度TOS说是8位其实有效的就只有4位这4位分别对应着最小延时最大吞吐量最高可靠性最小成本因为我们网络层的作用是规划一个最优的路线所以需要根据情况在这四种状态下切换。

416位总长度也就是64k,和UDP比较类似也就约束了我们一次性传输的上限就是64k那么如果我们想要传输较大的数据该怎么办呢

516位标记16位标记就是用来拆包的当我们想要传输较大的文件的时候我们可以把大的文件拆成一个一个小的文件

613位片偏移刚刚我们对一个数据进行了拆包之后那么问题又来了我们在进行组合的时候怎么知道谁在前谁在后呢我们的13位片偏移就解决了这个问题相当于给我们的每个包做了一个序号标记哪一个在前哪一个在后。

73位标志3位标志的目的是给我们的最后一个包做标记告诉我们这是最后一个包了。

88位生存时间我们的每个数据报在刚开始的时候都会有一个TTL(常见的12864)然后当我们每经过一个路由的时候其值就-1当其值减到0的时候所在的路由就会将其抛弃这样做是为了将一些到达不了的地址还在网络中传播的数据报给抛弃减少网络的阻塞。

98位协议告诉我们传输层使用的是哪一种协议是UDP还是TCP协议。

1016位首部校验和校验我们传送的数据是否正确。

地址管理 

源IP:发送人的地址。

目的IP:目的地的地址。

我们的IP地址占32位我们用三个点将其分成4份每一份所能表示的范围就是0-255。

其中IP地址又分为两个部分网络号+主机号。

网络号就是我们所处的网络而主机号就是我们所处网络的主机。

 子网掩码

子网掩码格式和IP地址一样也是一个32位的二进制数。其中左边是网络位用二进制数字“1”表示1的数目等于网络位的长度右边是主机位用二进制数字“0”表示0的数目等于主机位的长度。

 特殊的IP地址

1.如果主机号全是 0那么该 IP 就表示网络号局域网里的正常设备主机号不能为 0。
2.如果 IP 的主机号全是 1该 IP 就表示”广播地址“往这个广播地址上发的消息整个局域网中都能收到。
3.IP 地址是 127 开头的就表示”环回 IP“表示主机自己127.0.0.1环回 IP 中的典型代表。
4.IP 地址是 10 开头 或者 192.168 开头 或者 172.16-172.31 开头就表示该 IP 地址是一个局域网内部的 IP内网 IP。
5.除此之外剩下的 IP 称为 外网IP直接在广域网上使用的 IP要求外网IP 一定是唯一的每个外网 IP都会对应到唯一的一个设备内网 IP 只是在当前局域网中是唯一的不同局域网里可以有相同的内网 ip 的设备。

IP地址不够用问题

ipv4协议下的地址是32位也就是能够分配42亿九千万台的机子但是这个数量对于人类来说慢慢的就不够用了那么该怎么解决这个问题呢

1.动态分配 IP 地址每个设备连上网的时候才有 IP不联网的时候就没 IP这个IP就给别人用通过 动态IP 来解决 IP地址不够用的问题。

2.NAT 机制让多个设备去公用一个外网IP,就是把网络分成外网和内网外网是唯一的但是内网不是唯一的内网可以共用一个 外网的IP。也就是这里的外网 IP会给所有接入这个运营商设备的局域网都来使用这个 外网IP。外网区分内网的数据就是通过端口号来区分的。网络的连接是一个 五元组即使是 IP 相同也没事。

a对于一个 外网IP 来说可以在互联网的任意位置都能访问到
b对于一个 内网IP 来说只能在当前局域网内部访问就是 局域网1 的设备不能使用内网访问 局域网2 的设备。
c内网IP 是可以重复的只有在局域网内才是唯一的。
d不同的局域网访问的话就需要一个带有 外网IP 的机器然后 局域网1 把数据放到 外网服务器然后 局域网2 就可以访问到外网服务器就会修改 IP数据报把内网发出的 源IP改为 外网IP。
eNAT 也是存在极限的端口号个数是 65535如果一个局域网内的连接数超过了 65535这时候 NAT 就不一定好使了因为端口号不够用了。NAT 相当于是续命了并不是从根本解决。

IPV6庞大的地址数量可以彻底的解决当前的问题。

路由管理

路由选择也就是我们在网络层中路线的规划我们想要把数据传到指定的位置那就需要去规划路线。

我们数据在网络中传播的时候是不能一下子就知道具体的路线的而是走一步再看一步我们每走到一个路由器就会向其询问目的的路线如果知道那就告诉我们该怎么走如果不知道的话就会给我们一个大概的方向然后我们按照方向走到那个位置再去问新的路由器。

那么我们路由器是怎么知道的呢因为路由器内部维护了一个数据结构路由表记录了一些网段信息网络号以及每个网络号对于的网络接口。

数据链路层

数据链路层主要的协议是以太网。每个网卡都有 mac地址是唯一的在网卡出厂的时候就写死了以太网数据帧。

其中目的IP和源IP是6个字节表示我们数据传输过程中相邻的两个节点的mac地址这两个地址是不断的变化的。

MTU一个以太网数据帧能够承载的数据范围这个范围取决于硬件设备。以太网和硬件也是密切相关的不同的硬件设备对应的 数据链路层协议可能又不一样MTU 也不相同。MTU 对IP 的影响主要影响就是分包的过程。

MSSTCP 中在 IP 不分包的前提下最多搭配多少载荷
a一方面取决于 MTU。另一方面取决于 TCP 和 IP 的报头。
b当 TCP 传输的数据长度不高于 MSS 的时候是处于最高效的状态。
cARP 报文并不是用来传输数据的只是起到一个辅助的效果。
d路由器拿到一个 IP地址目的IP通过 IP地址来决定接下来这个数据咋走从哪个端口出去发到哪个设备上。
d所以就得决定接下来封装的以太网数据帧目的 mac 是啥需要根据 ARP协议建立起 IP -> mac 这样的映射关系。
e当设备启动的时候就会向局域网当中广播 ARP报文每个设备收到的时候都会做一个应答。
f应答信息中就包含了自己的 IP 和 mac发起广播的那一方就可以根据这些回应建立起这个映射表了。

特殊协议

DNSDNS是一个应用层的协议主要是为了对域名进行解析对于一些难记的地址就可以使用一串英文单词来表示这个 ip地址这串英文单词就叫做域名。域名和 IP地址 之间是一一对应的关系。

DNS 系统DNS 系统最开始的时候只是一个普通文件称为 hosts 文件。

现在 hosts 文件已经不使用了因为域名太多了不可能去一直修改 host 文件。于是有了一个机构专门负责处理这些 域名 和 IP 的对应关系。如果想要对域名进行解析的话就访问一下这个服务器域名解析服务器就好了每个城市都会有镜像服务器我们一般都是在访问镜像服务器。

当我们的主机查询了 DNS 之后主机就会把这个查询结果缓存一定的时间浏览器来进行缓存下次再访问到同一个域名的时候就可以省略查询 DNS 的过程了。

NATP:这个就是当 端口号重复时的情况它的处理机制就是 NAPT。

这种关联关系也是由NAT路由器自动维护的。
例如在TCP的情况下建立连接时就会生成这个表项
在断开连接后就会删除这个表项 

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6