当前位置: 首页 > news >正文

一文看懂TCP/IP中的相关知识

文章目录

          • 前言
          • IP基础知识
            • 什么是IP?
            • IP的分类
            • 子网掩码
          • 计算机间通信
            • MAC地址
            • ARP & 内网通信
            • 私有IP如何与公网通信
          • UDP & TCP
            • UDP
            • TCP
            • TCP三次握手
            • TCP四次挥手
            • TCP传输数据包过程分析
            • 拥塞控制
          • 技术详解
            • DHCP(动态主机配置协议)
            • NAT

前言

学习到的东西如果能以自己的方式讲述出来,那就是真的理解了。记得没有学习计算机网络相关知识之前,对于这个模块的东西一片混沌,什么私有Ip,公网IP,路由器、交换机,MAC地址换七八糟的弄得我头大,后来经过系统的学习终于整明白了,写个博客分享一下吧!原创不易,且行且珍惜。

IP基础知识

对这部分知识了解的可以跳过。

什么是IP?

IP地址(英语:Internet Protocol)是一种在Internet上的给主机编址的方式,也称为网际协议地址。例如IP:119.23.27.40,被**.**分成四个部分,每个部分8bit,所以IP地址是32bit的。

IP的分类

最开始设计IP的时候并没有想到如今的计算机如此普及,而IP的数量是有限的,为了让有限的IP供全球使用,想了这样一个办法:
根据网络号将IP地址分为A、B、C、D、E五类,前三类地址的范围如下:
在这里插入图片描述
在这个分类中又保留了一些私有IP段,我们的计算机联网的时候可以通过私有IP和公有IP,他们的区别就在于公有IP是唯一的,但是私有IP只需要保证在局域网内唯一,可以想想,通过这样的技术,一个公有IP内部就可以接入很多的私有IP,每类的每个公有IP内部可以分配的私有IP数如上表中所示。根据这个最大的主机数就可以让这些IP使用在不同的网络布局,A、B、C分别适用大型网络;中型网络;小型网络。就如同家里的路由器,一般家里的联网设备不会超过254个,一般都是192.168.1.*。

子网掩码

通过上述的方式解决我们的IP地址不够用的问题,但是我们发现一个小问题,C类的IP地址能链接的最大主机数254个,如今一个网吧都不够分的吧!B类地址又能够达到65534个主机,一般的企业都用不到那么多,剩下的就浪费了。
为了解决这个问题,引入了一项技术叫做无类型域间选路(CIDR)。使用这种技术,IP地址由两部分组成,网络号和主机号,比如有时候我们会看到这样的IP:10.0.0.111/24,这种形式的就是CIDR,其中24就代表前面的24位是网络号,另外八位就是主机号。CIDR使得子网掩码出现了,比如255.255.255.0,子网掩码和IP地址进行与操作就可以得到我们的网络号。

计算机间通信

计算机通信分为内网和需要经过公网,在将通信之前先要先明白几个概念。

MAC地址

在将计算机间的通信之前,我们先来看看什么是MAC地址。每台计算机都配有网卡,每块网卡在出厂就带着一块网卡,MAC地址是由16进制数字组成的物理地址,是全球唯一的,比如下图中所示:
在这里插入图片描述
那为什么不直接用MAC地址通信?只能说想法是天真的,就像是你知道一个人的名字就可以找到他吗?你需要他的住址,根据住址一步一步的找到他,MAC地址就相当于名字,而IP就是那个地址,在Internet中,通过对IP地址的一次一次的路由,通过各种算法的解析,才能到目标地。而MAC地址在公网中又不能拿来做路由。

ARP & 内网通信

拥有了MAC地址之后,在局域网的内部,比如A(192.168.1.2)机器要向B(192.168.1.3)发送请求。那么A如何发送?我们知道网络的分层:从上到下为应用层、表示层、会话层、传输层、网络层、数据链路层,其中IP地址是网络层,MAC地址是数据链路层,两台机器要想通信,必须要保证下层不缺失。此处A想要和B通信,而A只有B的IP,要想通信,就必须拿到B的MAC地址,A通过ARP协议在局域网内发送广播就可以获取到B的MAC地址,然后在数据包中填写MAC地址,然后将请求发送给B,从而实现局域网内部通信。

私有IP如何与公网通信

当然,私有IP是不能直接在公网中通信的,不然的话,不同局域网相同的IP不就冲突了。为了解决私有IP通信的为题,有了一个东西叫做网关(Gateway)。他可以根据你的目标IP是否和你在同一个网络段而判断出目标是否和你在一个局域网,如果在一个局域网,就像上面描述的局域网通信一样,如果不是同一个网段的,那就比较复杂了。
比如我们的路由器,它分为内网入口和外网入口,我们家里的设备插入到内网入口,路由器通过DHCP(看技术详解部分)就会给我们的设备分配内网IP,在公网入口我们需要配置运营商给的公网IP。
在这里插入图片描述
如图所示:A访问C,A首先判断119.23.27.40是否在同一个网段,不是的话,就获取A配置的网关的MAC地址,数据包中的内容就是:

  • 源MAC地址:A的MAC地址
  • 目标MAC:网关的MAC
  • 源IP:192.168.1.2
  • 目标IP:119.23.27.40
    然后A将数据包发送出去,网关收到数据包后,将私有的IP192.168.1.2改为公网IP119.23.27.20,然后根据配置的路由协议选择下一跳,图中省略了N多哈,网关就通过ARP获取C的MAC地址,数据包中的信息更改为:
  • 源MAC地址:网关的MAC地址
  • 目标MAC:C的MAC
  • 源IP:119.23.27.20
  • 目标IP:119.23.27.40

C获取请求处理请求,以同样的方式将数据包返回给A设备,我们可以看到,私有IP上网需要通过网关转换成公网IP,在公网IP中以直接转发的方式进行路由,这里还有有个问题,设备C返回请求,数据包最多只能到达网关,因为设备C只有网关的IP,那么我们平时使用的时候是如何实现数据返回的呢?那么就有种技术叫做NAT,在技术详解部分说明。

UDP & TCP

在这里插入图片描述
前面讲计算机之间的通信的时候主要从七层协议的数据链路层和网络层讲述的,但是实际在通信的时候肯定不能简单的数据包能够传输到目的地机器就可以了的,卸下MAC头,IP头,我们还需要根据不同应用,不同端口,数据包发送给不同的进程。而我们的UDP和TCP就是位于更高一层的传输层,然后我们讲讲这两种协议。

UDP

UDP是面向无连接的,它不能保证数据一定到达,发到网络中就不管了。所谓的连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。我们可以看下UDP的头:
在这里插入图片描述
在卸下IP头里会有个8bit的协议说明是TCP还是UDP,根据协议读取包中的数据。无论是TCP还是UDP,内核都会通知监听这个端口的应用读取数据,这也是为什么监听的端口不能冲突,操作系统需要根据不同的端口发送数据到不同的具体应用。UDP中目标机器收到数据过后也不会回复消息,所以在通信的两端都是没有状态的,相对于TCP来说UDP是比较简单的。

TCP

TCP是面向连接的,它提供可靠的服务,确保每个数据包无差错,不丢失,且按照规定次序排列好,在通信的两端都会标记数据包的收发状态,所以TCP是有状态的。我们先来看下TCP的包头与UDP有什么差异,看了图过后来了句wc,请问哪里是一样的?还真有,端口是必不可少的。
在这里插入图片描述
我们在写拿java写web项目的时候传输对象时需要实现序列化才能在网络上传输,这里的序号就是干这个的,包到达目的地后能够维持包的正确顺序,确认序号可以反应包是否到达,是否需要重发,TCP不是保证包不丢失嘛,就要有相应的数据结构来支撑它的这个特性。上文还说到TCP是面向连接的,那么TCP首先就要通过三次握手四次挥手完成TCP的连接。先认识下包头中的位,URG:SYN:发起连接,ACK:回复,RST:重新连接,FIN:结束连接。然后我们再来看下具体的握手挥手过程。

TCP三次握手

在这里插入图片描述
最开始客户端和服务端都是closed状态,服务端应用首先启动,监听端口,处于listen状态,客户端发起连接syn处于syn-sent状态,服务端收到连接ACK接收SYN并且返回SYN处于SYN-RCVD状态,客户端收到服务端发送的SYN和ACK,发送ACK的ACK,处于established状态,服务端收到ACK的ACK也处于established状态,到此,客户端和服务端分别都完成了一发一收,连接建立完成。

TCP四次挥手

在这里插入图片描述
客户端A,服务端B。A要断开连接时发送消息给B然后进入FIN_WAIT_1状态,B接收到消息进入CLOSE_WAIT状态,A收到B的回复进入FIN_WAIT_2状态,这个时候叫做半关闭。B要断开连接时也发送消息,A收到消息后结束状态并发送ACK(会要求A等待一段时间,让B收到ACK或者重发),B收到后结束通讯。
当然我们只是分析的正常情况下的断开连接的程序,如果中途发生异常,那就要另当别论了。

TCP传输数据包过程分析

三次握手完成之后便是我们数据包的正式传输,TCP可是能够做到包不丢失、流量控制、保证有序的,那么它如何做到,我们来看下TCP具体的实现方法。
在这里插入图片描述

  • LastByteAcked:第一部分和第二部分的分界线
  • LastByteSent:第二部分和第三部分的分界线
  • LastByteAcked + AdvertisedWindow:第三部分和第四部分的分界线

在这里插入图片描述

  • MaxRcvBuffer:最大缓存的量;
  • LastByteRead之后是已经接收了,但是还没被应用层读取的;
  • NextByteExpected是第一部分和第二部分的分界线。

如上图所示,TCP中,需要在网络中传输的包都是有序号的,所有的包在发送端以及接收端分为图中的几个部分。首先接收端会给发送端一个窗口的大小(AdvertisedWindow),也就是图中指明的大小,这个AdvertisedWindow size接收端如何计算的呢?看图中,接收端是有个MaxRcVBuffer大小的,不过由于有些包已经接收确认但是应用还来不及读取,所以AdvertisedWindow size = MaxRcvBuffer - NextByteExpected。接收端只有和第一部分是连续的才会回复,就算后面的已经到达也不会回复如果包丢失也会通过某些机制(超时重传、自适应重传等)重新传送。

拥塞控制

从接收端Advertised Window size的计算过程我们能发现一个问题,如果未被应用读取的数据包变多,因为MaxRcvBuffer肯定是固定的嘛,那么Advertised Window size就会变小,到最后甚至为0导致发送端暂定发送,因此TCP使用拥塞窗口和滑动窗口共同调节发送的速度(使用公式,LastByteSent - LastByteRead <= min{cwnd,rwnd})。

TCP通过拥塞控制避免包丢失和超时重传现象,一旦出现这种现象就说明发送过快,网络条件不好。那如何控制发送的速度,使用慢启动:也就是将cwnd设置为一个报文段,当收到确认过后cwnd+1,第二次就可以发动两个,然后发送速度就是指数级的,当发送速度赶上一个值ssthresh为65535个字节,超过这个值的时候,就减缓增加的速度,每次增加1/cwnd,当cwnd个确认过后,就增加一个cwnd,这样就变成了线程增长,总有一天,还是会出现拥塞,然后又回到开始,cwnd设置为1再次慢启动。当然这样会导致速度成为过山车。一般在快速重传算法情况下,cwnd会变成cwnd/2,sshthresh = cwnd,速度就不会起伏的那么高了。现在的TCP BBR拥塞算法就是希望找到填满管道,但是不填充缓存的这一个平衡点来达到高贷款和低延时。

技术详解

这个部分对我们文中使用到的技术进行简单的讲述。

DHCP(动态主机配置协议)

首先,通过手动设定IP的操作绝对是可行的,不过你要不怕麻烦,如果你抱着电脑在寝室和团队间来回用,每一次用都得配置下IP。为了减少麻烦,就有了DHCP,感觉就像马云说的话 ”世界是懒人创造的“。DHCP的工作原理是这样的:
当一台机器A要申请IP的时候,目前A只有自己的MAC地址,它使用IP:0.0.0.0发送广播包给IP 255.255.255.255,这个过程叫做DHCP Discover。网络中的DHCP Server看到过后,就会分配一个设置好的共享IP给机器A,同样使用广播的方式,并且DHCP Server会标记这个IP不被其他的机器使用,这个过程叫做DHCP offer。如果有多个DHCP Server发送offer,机器A选择一个进行确认,最后A就获得了IP地址。

NAT

NAT就是网络地址转换,当我们私有IP需要和公网进行通信的使用,网关使用NAT将我们的私有IP转化为公网IP,从而使得多台机器共享一个公网IP,这样就能解决公网IP有限的问题。还记得下图的例子吗?C设备只有A的公网IP,C是如何将数据发送给A的?怎么确认这个数据包就是返回给A的?
在这里插入图片描述
答案设计到NAT的具体实现,NAT的分类一般有三种静态NAT、动态地址NAT、网络地址端口转换NAPT

  • 静态NAT:私有IP与公有IP具有一一对应的关系并且记录在静态的转化表中,不过这样的话就需要大量的公网IP。
  • 动态地址NAT:公网IP较少,私有机器较多,这样的话私有IP与公网IP就是多对一的关系,还是记录在转换表中,不过转换表是动态的。
  • NAPT:这是最常用的方式,通过将私有IP映射到公网IP的不同端口上,这个端口由NAT设备选定。

http://www.taodudu.cc/news/show-8456977.html

相关文章:

  • 开发数据产品+AI产品通关上岸课程
  • AI产品经理-借力
  • 七种令人惊叹的人工智能工具
  • cin.ignore()
  • delete 与 delete[ ] 区别
  • C++信号处理 [ signal()函数 raise()函数 ]
  • C++存储类
  • 第13章 宣泄的拥抱
  • 【附源码】Java计算机毕业设计喜枫日料店自助点餐系统(程序+LW+部署)
  • Java实现餐厅自助点餐系统【附源码】
  • 微信小程序java高校食堂窗口自助点餐系统uniapp
  • 基于微信小程序的食堂窗口自助点餐系统设计与实现-计算机毕业设计源码+LW文档
  • 自助点餐系统(三)
  • JAVA实现自助点餐系统【附源码】
  • 【Vue H5项目实战】从0到1的自助点餐系统—— 项目页面布局(Vue3.2 + Vite + TS + Vant + Pinia + Nodejs + MongoDB)
  • P5706 【深基2.例8】再分肥宅水 C语言
  • 再分肥宅水
  • (JAVA)P5706 【深基2.例8】再分肥宅水
  • 【洛谷算法题】P5706-再分肥宅水【入门1顺序结构】Java题解
  • 洛谷P5706 再分肥宅水
  • (已更新)市肥宅中心论坛类小程序源码 apache协议开源
  • 从Hello world到算法! 第12题【再分肥宅水】
  • 知乎网论文重查入口 快码论文
  • 维普论文查重入口降重
  • 维普论文查重入口官网?paperpass降重后的报告怎么下载
  • 犹如白皮书般详细的Css文本控制总结
  • IDT + FisherVector (by C++)我的实践
  • java语言中数组中的每个数据称为_一、Java语言基础(4)_方法和数组——数组...
  • 不悔梦归处,只恨太匆匆
  • 第12期 《不悔梦归处》7月刊