PART1:计算机网络体系可以大致分为一下三种,
了使得多种设备能通过网络相互通信,和为了解决各种不同设备在网络互联中的兼容性问题,国际标准化组织制定了开放式系统互联通信参考模型
】
应用层主要提供两个终端设备上的应用程序之间信息交换的服务,它定义了信息交换的格式,消息会交给下一层传输层来传输。 我们把应用层交互的数据单元称为报文
。
应用层是工作在操作系统中的用户态,传输层及以下几层则工作在内核态
每获取次数据,就要执行一次连接、发送请求消息、接收响应消息、断开的过程
。浏览器与Web服务器之间收发消息的过程中实际负贵收发消息的是协议栈、网卡驱动和网卡,只有这3者相互配合,数据才能够在网络中流动起来
。
上connect是客户端选择了一个可用端口,然后向服务器发起握手请求了。同时自己还开了个定时器,如果逾期收不到反馈会重试
。客户端发起连接请求之后,三次握手的工作就由双方的内核完成了。三次握手成功之后,服务器端会创建一个sock对象,在它上面保存好tcp连接的四元组信息,然后放在接收队列中
。再后面就是在这个连接之上的读和写了。用户流程只需要发起读写请求就好了,放到接收缓存或者发送缓存中。真正的读写,重试都由内核从缓存中取数据,或者写入。首先服务器一方启动后先创建出套接字
。客户端创建套接字的操作非常简单,只要调用Socket库中的socket程序组件就可以了。和调用解析器一样,调用socket之后,控制流程会转移到socket内部并执行创建套接字的操作,完成之后控制流程又会被移交回应用程序。只不过,socket的内部操作并不像解析器那样简单。程序组件其实内部就放了一堆方法呗
**。当调用Socket库中的程序组件时,应用程序所指定的参数会通过Sacket库的程序组件传递给协议栈,并由协议栈来实际执行相应的操作。socket_create、socket_connect、socket_bind、socket_listen、socket_accept、socket_read、socket_write、socket_close
协议栈会返回一个描述符,应用程序会将收到的描述符存放在内存中
。
给某个套接字分配的编号
。也许光说编号还不够形象,大家可以想象一下在酒店寄存行李的场景,酒店服务人员会给你一个号码牌,向服务人员出示号码牌,就可以取回自己寄存的行李,描述符的原理和这个差不多。当创建套接字后,我们就可以使用这个套接字来执行收发数据的操作了。这时,只要我们出示描述符,协议栈就能够判断出我们希望用哪一个套接字来连接或者收发数据了。应用程序是通过“描述符”这一类似号码牌的东西来识别套接字的
**。名为connect的程序组件
来完成这一操作。这里的要点是当调用connect时,需要指定描述符、服务器IP地址和端口号这3个参数。
负责向两台终端设备进程之间的通信提供通用的数据传输服务
【假设我们需要在 A 电脑的进程发一段数据到 B 电脑的进程,我们一般会在代码里使用 socket 进行编程。这时候,我们可选项一般也就TCP 和 UDP 二选一。TCP 可靠,UDP 不可靠。 除非是马总这种神级程序员(早期 QQ 大量使用 UDP),否则,只要稍微对可靠性有些要求,普通人一般无脑选 TCP 就对了
。】。 应用进程利用该服务传送应用层报文。“通用的”是指并不针对某一个特定的网络应用,而是多种应用可以使用同一个运输层服务。】因此需要⽤⼀个编号将应⽤区分开来,这个编号就是端⼝
运输层主要有以下两种协议:
TCP传输控制协议在IP协议的基础上增加了确认重发、滑动窗口和复用等机制,提供了稳定的、安全的、面向连接【传输数据前先建立连接】的字节流【基于字节流的服务没有字节序问题的困扰】服务
。
或者说TCP有三大特点:
【因为IP 层是不可靠的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性,所以如果需要保障网络数据包的可靠性,那么就需要由上层(传输层)的 TCP 协议来负责。】
SOCK_STREAM,是指使用字节流传输数据,说白了就是TCP 协议
。
字节流可以理解为一个双向的通道里流淌的二进制数据,也就是 01 串 。纯裸 TCP 收发的这些 01 串之间是 没有任何边界 的,你根本不知道到哪个地方才算一条完整消息,没有边界就会出现出界情况,拿多了或者少拿了
。)】,所以纯裸 TCP 是不能直接拿来用的,需要 在这个基础上加入一些 自定义的规则 ,用于区分 消息边界
。加入 消息头【消息头 ,还可以放各种东西,比如消息体是否被压缩过和消息体格式之类的,只要上下游都约定好了,互相都认就可以了,这就是所谓的 协议。每个使用 TCP 的项目,比如咱们的RPC项目,都可能会定义一套类似这样的协议解析标准,他们可能有区别,但原理都类似。于是基于 TCP,就衍生了非常多的协议,比如 HTTP 和 RPC。】
,消息头里写清楚一个完整的 包长度是多少
,根据这个长度可以继续接收数据,截取出来后它们就是我们真正要传输的 消息体 。上一个包的内容与下一个包里的数据粘在了一起被错误地当成了一个数据包解析了出来。这就是所谓的粘包
。】【用层传到 TCP 协议的数据,不是以消息报为单位向目的主机发送,而是以字节流的方式发送到下游,这些数据可能被切割和组装成各种数据包,接收端收到这些数据包后没有正确还原原来的消息,因此出现粘包现象。】
MSS
(TCP 最大报文段长度) ,就要将数据包分块,这样即使中途有一个分块丢失或损坏了,只需要重新发送这一个分块,而不用重新发送整个数据包
。在 TCP 协议中,我们把每个分块称为一个 TCP 段(TCP Segment)。
网络层中一个网络包【也就是一个IP报文:传输层的报文或者说数据部分+IP包头】的最大长度,以太网中一般为 1500 字节
。【由网络接口层(数据链路层)提供给网络层,一般认为是的MTU(1500),直接传入整个消息,会超过水管的最大承受范围,那么,就需要进行切片,成为一个个数据包,这样消息才能正常通过“水管”。每一层都增加了各自的协议头,那自然网络包的大小就增大了,但物理链路并不能传输任意大小的数据包,所以在以太网中,规定了最大传输单元(MTU)是 1500 字节,也就是规定了单次传输的最大 IP 包大小。
】传输层中TCP
最大报文段长度:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度
。【应用需要传输的数据可能会非常大,如果直接传输就不好控制,因此当传输层的数据包大小超过 MSS(TCP 最大报文段长度) ,就要将数据包分块,这样即使中途有一个分块丢失或损坏了,只需要重新发送这一个分块,而不用重新发送整个数据包。在 TCP 协议中,我们把每个分块称为一个 TCP 段(TCP Segment)
。】接收数据端的应用层没有及时读取 TCP Recv Buffer 中的数据,从而不确定消息的边界。接收端在面对"无边无际"的二进制流的时候,根本不知道收了多少 01 才算一个消息。一不小心拿多了就说是粘包。
其实粘包根本不是 TCP 的问题,是使用者对于 TCP 的理解有误导致的一个问题。】,所以只要在发送端每次发送消息的时候给消息带上识别消息边界的信息,接收端就可以根据这些信息识别出消息的边界,从而区分出每个消息
。TCP协议如何保证可靠性?----TCP主要提供了检验和、序列号/确认应答、超时重传、滑动窗口、拥塞控制和 流量控制等方法实现了可靠性传输。
检验和
:通过检验和的方式,接收端可以检测出来数据是否有差错和异常
,假如有差错就会直接丢弃TCP段,重新发送。序列号/确认应答
:序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序
,并且去掉重复序列号的数据
。
都会对传输方进行确认应答。也就是发送ACK报文
,这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发
。滑动窗口
:滑动窗口既提高了报文传输的效率,也避免了发送方发送过多的数据而导致接收方无法正常处理的异常。TCP 协议需要对数据进行确认后,才可以发送下一个数据包
。这样一来,就会在等待确认应答包环节浪费时间。(为了避免这种情况,TCP引入了窗口概念。窗口大小指的是不需要等待确认应答包而可以继续发送数据包的最大值
)
会将数据分段,然后再给每段加上首部字段后再去传输
,此时**分段后加上首部字段形成的信息包称为分组
**,每层都有自己(自己按照自己目的加工出来的)的分组滑动窗口起到了一个限流的作用,也就是说当前滑动窗口的大小决定了当前 TCP 发送包的速率,而滑动窗口的大小取决于拥塞控制窗口和流量控制窗口的两者间的最小值
超时重传
:超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被认为是丢包了,需要重传。最大超时时间是动态计算的ARQ 协议
: 也是为了实现可靠传输的,ARQ 协议的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组
。
它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。ARQ 包括停止等待 ARQ 协议和连续 ARQ 协议
拥塞控制
:在数据传输过程中,可能由于网络状态的问题,造成网络拥堵,此时引入拥塞控制机制,在保证TCP可靠性的同时,提高性能拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个
。】。当cwndssthresh时,改用拥塞避免算法
为了防止cwnd增长过大引起网络拥塞,还需设置一个慢启动阀值ssthresh(slow start threshold)状态变量
。当cwnd到达该阀值后,就好像水管被关小了水龙头一样,减少拥塞状态。即当cwnd >ssthresh时,进入了拥塞避免算法
。一般来说,慢启动阀值ssthresh是65535字节,cwnd到达慢启动阀值后:每收到一个ACK时,cwnd = cwnd + 1/cwnd,当每过一个RTT时,cwnd = cwnd + 1
流量控制
:用来解决发送方一直发送数据,但是接收方处理不过来怎么办【流量控制是为了控制发送方发送速率,保证接收方来得及接收】
?如果主机A 一直向主机B发送数据,不考虑主机B的接受能力,则可能导致主机B的接受缓冲区满了而无法再接受数据【双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来。如果接收方处理不过来的话,就只能把处理不过来的数据存在 接收缓冲区(Receiving Buffers) 里(失序的数据包也会被存放在缓存区里)。如果缓存区满了发送方还在狂发数据的话,接收方只能把收到的数据包丢掉。出现丢包问题的同时又疯狂浪费着珍贵的网络资源。因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。】,从而会导致大量的数据丢包,引发重传机制
。而在重传的过程中,若主机B的接收缓冲区情况仍未好转,则会将大量的时间浪费在重传数据上,降低传送数据的效率
。所以引入流量控制机制,主机B通过告诉主机A自己接收缓冲区的大小
,来使主机A 控制发送的数据量
。流量控制与TCP协议报头中的窗口大小
** 有关
每次接收方接受到数据后会将剩余可处理数据的大小告诉发送方
(比如接受方滑动窗口可用大小为400字节,发送方发送过来100字节的数据,那么接收方剩余可用滑动窗口大小就为300字节,这是发送方就知道下次返送数据的大小范围了。)。接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据
。
数据会存放在缓冲区,但是这个缓冲区是操作系统控制的,当系统繁忙的时候,会缩减缓冲区减小,可能就会造成丢包的问题(上面那个虽然说是主机B的接受缓冲区满了无法接收数据才导致大量数据丢失,但是这里缩减缓冲区导致丢包其实和缓冲区满一样)
。我们会发现,这个问题发生的原因就是减少了缓存,又收缩了窗口大小,所以 TCP 是不允许同时减少缓存⼜收缩窗⼝的
。三次握手有四种状态、四次挥手中有七种状态,总共11中状态
就是因为下面TCP 的三次握手机制(TCP 建立连接的过程)
:TCP 传输数据之前,要先三次握手建立连接【在 HTTP 传输数据之前,首先需要 TCP 建立连接,TCP 连接的建立,通常称为三次握手
】【三次握手目的是保证双方都有发送和接收的能力
】客户端–--->发送带有 SYN 标志的数据包–一次握手–---->服务端
】:除了图中一握做的四件事之外(客户端向服务器发一个同步报文其实也就是将同步位 SYN 设置为 1),Client的TCP进程创建一个传输控制块 TCB ,然后向Server发出连接请求报文段,客户端进入同步已发送状态
。先是服务端主动监听某个端口,并且服务器处于LISTEN状态
。然后客户端随机初始化序列号seq=x
,然后将这个随机初始化的序列号置于
TCP首部的序号字段中,同时把SYN标志位置为1【SYN=1表示这是一个连接请求的报文
】,接着把第一个SYN请求连接报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT状态
服务端–----->发送带有 SYN/ACK 标志的数据包–二次握手–------>客户端
】:服务器收到连接请求报文段,如果同意建立连接,则向客户端发送同步确认报文。在确认报文段中同步位 SYN=1、确认位 ACK=1、确认号 ack=x+1,同时也为自己选择一个初始序列号 seq=y,这时服务器进入 SYN-RCVID 状态
服务端也随机初始化自己的序列号seq=y
并将这个序列号填入TCP首部的序号字段中,然后再把TCP首部的确认应答号字段填入client_isn + 1【也就是ack,这个确认应答号不就是上一次的seq + 1嘛,不就是x+1】,并接着把SYN和ACK标志位置为1
.最后把该不包含应用层数据的报文发给客户端,之后服务端处于SYN-RCVD状态
。客户端–----->发送带有带有 ACK 标志的数据包–三次握手–----->服务端
】:客户端收到 服务器的确认以后,再向服务器发出确认报文。确认报文 ACK=1、确认号ack=y+1。这时客户端进入到 ESTAB-LISHED 状态
。当服务器接收到客户端的确认后,服务器也进入 ESTAB-LISHED 状态
。连接建立完成ACK标志位置为1
,其次确认应答号字段ack=上一次的随机序列号seq + 1 = y + 1,最后把确认报文发给服务端,这次报文可携带客户到服务器的数据,之后客户端处于ESTABLISHED状态
服务器收到确认报文后也进入ESTABLISHED状态
。第三次握手是可以携带数据的,前两次握手是不可以携带数据的
。一旦完成三次握手,双方都处于 ESTABLISHED 状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。状态机
,在连接建立的过程中,双方的状态变化时序图就是左右那些框里的字母。
netstat -napt 命令
查看。内核会把该连接存储到半连接队列
,然后再向客户端发送 SYN+ACK 包,接着客户端会返回 ACK,服务端收到第三次握手的 ACK 后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其增加到全连接队列
,等待进程调用 accept() 函数时把连接取出来。也就说,全连接队列指的是服务器与客户端完了 TCP 三次握手后,还没有被 accept() 系统调用取走连接的队列。而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的
。】,而不是两次或者四次:主要有三个原因【通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。】
三次握手的首要原因是为了防止已过期或者已经失效的连接请求报文突然又传送到服务器,因而产生错误和资源浪费
。
如果客户端连续发送多次 SYN 建⽴连接的报⽂,如果出现了网络拥堵,可能会有旧连接先于新连接到达的情况,就可能会出现连接覆盖,要避免这种情况,最少需要三次握手【三次握手可以保证在被动发起方发送数据前,也就是建立连接之前,阻止掉历史连接,这样就不会造成资源浪费】
此时姗姗来迟的 之前那个A 报文段才到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,但是已经进入 CLOSED 状态的客户端无法再接受确认报文段,更无法进入 ESTABLISHED 状态,这将导致服务器长时间单方面等待,造成资源浪费
。才能让双方均确认自己和对方的发送和接收能力都正常
。Client确认自己收发、对方收发能力正常+Server确认自己收发、对方收发能力正常
自己收、客户端发
”能力正常;“自己发、自己收、服务端收、服务端发”
能力正常**;Server 确认了:对方发送正常,自己接收正常“自己发、客户端收”
能力正常,对方发送能力和接收能力正常;告知对方自己的初始序号值,并确认收到对方的初始序号值(同步双⽅初始序列号)
:
序号字段和确认序号字段
,通过这两个字段双方都可以知道在自己发出的数据中,哪些是已经被对方确认接收的,这样一来一回,才能确保双方的初始序列号能被可靠的同步。
。这两个字段的值会在初始序号值得基础递增,如果是两次握手,只有发起方的初始序号可以得到确认,而另一方的初始序号则得不到确认
。如果客户端迟迟没有收到第二次握手,那么客户端就觉得可能自己的 SYN 报文(第一次握手)丢失了,于是客户端就会触发超时重传机制,重传 SYN 报文
。SYN 同步序列编号(Synchronize Sequence Numbers) 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务器之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务器使用 SYN-ACK 应答表示接收到了这个消息,最后客户机再以 ACK(Acknowledgement)消息响应
。这样在客户机和服务器之间才能建立起可靠的 TCP 连接,数据才可以在客户机和服务器之间传递这些信息的组合,包括Socket、序列号和窗口大小称为连接
。】是需要客户端与服务器端达成(用于保证可靠性和流量控制维护的某些状态信息:Socket、序列号和窗口大小)的共识。这些信息的组合就称为连接。
源 IP 地址是随机的
,基本上可以断定这是一次 SYN 攻击。
发送大量的半连接请求
,耗费 CPU 和内存资源,大概原理是:
重新发送SYN+ACK包,以便客户端重新发送ACK包
。 如果重发指定次数之后,仍然未收到 客户端的ACK应答,那么一段时间后,服务端自动关闭这个连接。客户端向服务端发送一个TCP首部FIN标志被置为1的连接释放报文段FIN报文,说我客户端打算关闭连接,(这个连接释放报文段首部的终止控制位FIN=1,ACK=1)
,主动关闭连接,此时客户端进入FIN-WAIT-1(终止等待1)状态
,同时等待服务端的确认:
服务端立即发出确认报文段(ACK=1)
,序列号 seq = k(等于服务端发送数据的最后一个序号加1),确认号 ack = u + 1。此时服务端进入CLOSE-WAIT(关闭等待)状态
TCP 连接处于半关闭状态
,即客户端到服务端的连接已经释放了,但是服务端到客户端的连接还未释放。这表示客户端已经没有数据发送了,但是服务端可能还要给客户端发送数据。客户端收到服务器的确认报文后进入FIN-WAIT-2(终止等待2)状态,继续等待服务端处理完数据并发出连接释放报文段
),服务端主动关闭连接
,同时等待客户端的确认。若服务端已经没有数据要发送,服务端就会向客户端发送连接释放报文段FIN报文
,段首部的终止控制位 FIN=1,序号 seq=w(半关闭状态可能又发送了一些数据),确认号 ack=u+1,这时服务端进入 LAST-ACK(最后确认)状态
,等待客户端的确认。
序列号 seq = w
,即服务端上次发送的报文的最后一个字节的序号 + 1。确认号 ack = u + 1
,与第二次挥手相同,因为这段时间客户端没有发送数据确认报文(确认段中确认位ACK=1)
,序列号 seq = u + 1
,确认号为 ack = w + 1。
。然后客户端就进入了 TIME-WAIT(时间等待) 状态
。而 服务端只要收到客户端发出的确认,就立即进入 CLOSED 状态,至此服务端已经完成连接的关闭
。注意此时客户端到 TCP 连接还没有释放,必须经过 2*MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态,至此客户端也完成连接的关闭
。
注意此时客户端到 TCP 连接还没有释放,必须经过 2*MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态
。而**服务端只要收到客户端发出的确认,就立即进入 CLOSED 状态
**。可以看到,服务端结束 TCP 连接的时间要比客户端早一些。超时重传 FIN/ACK 报文
,此时如果客户端已经断开了连接,那么就无法响应服务端的二次请求,这样服务端迟迟收不到 FIN/ACK 报文的确认,就无法正常断开连接。MSL 是报文段在网络上存活的最长时间。客户端等待 2MSL 时间,即「客户端 ACK 报文 1MSL 超时 + 服务端 FIN 报文 1MSL 传输」,就能够收到服务端重传的 FIN/ACK 报文,然后客户端重传一次 ACK 报文,并重新启动 2MSL 计时器。如此保证服务端能够正常关闭。
,如果服务端重发的 FIN 没有成功地在 2MSL 时间里传给客户端,服务端则会继续超时重试直到断开连接。【因为这个 ACK 是有可能丢失的,会导致服务器收不到对 FIN-ACK 确认报文
。假设客户端不等待 2MSL ,而是在发送完 ACK 之后直接释放关闭,一但这个 ACK 丢失的话,服务器就无法正常的进入关闭连接状态。】再经过时间 2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段
。或者即使收到这些过时的报文,也可以不处理它。【】一般情况下,都是客户端所处的状态;
**服务器端一般设置不主动关闭连接。TIME_WAIT 需要等待 2MSL,在大量短连接的情况下,TIME_WAIT会太多,这也会消耗很多系统资源
。对于服务器来说,在 HTTP 协议里指定 KeepAlive(浏览器重用一个 TCP 连接来处理多个 HTTP 请求),由浏览器来主动断开连接,可以一定程度上减少服务器的这个问题。或者说为什么是四次握手
)任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B 回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。
。】请求关闭连接。服务器的ACK和FIN一般都会分开发送
,从而导致多了一次,因此一共需要四次挥手。三次握手阶段、四次挥手阶段的包丢失了怎么办?如“服务端重发 FIN丢失
**”的问题。)
UDP 用于对高速传输和实时性有较高要求的通信。TCP 和 UDP 应该根据应用目的按需使用。
不保证数据包是否能抵达对方,但它实时性相对更好,传输效率也高
UDP是基于数据报是指无论应用层交给 UDP 多长的报文,UDP 都照样发送,即一次发送一个报文。至于如果数据包太长,需要分片,那也是IP层的事情,大不了效率低一些。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。而接收方在接收数据报的时候,也不会像面对 TCP 无穷无尽的二进制流那样不清楚啥时候能结束。正因为基于数据报和基于字节流的差异,TCP 发送端发 10 次字节流数据,而这时候接收端可以分 100 次去取数据,每次取数据的长度可以根据处理能力作调整;但 UDP 发送端发了 10 次数据报,那接收端就要在 10 次收完,且发了多少,就取多少,确保每次都是一个完整的数据报。并且在报头中有16bit用于指示 UDP 数据报文的长度,假设这个长度是 n ,以此作为数据边界。因此在接收端的应用层能清晰地将不同的数据报文区分开,从报头开始取 n 位,就是一个完整的数据报,从而避免粘包和拆包的问题。
。TCP面向连接
(如打电话要先拨号建立连接) ;UDP是无连接的,即发送数据之前不需要TCP提供可靠的服务
。也就是说,通过TCP连接传送的数据【TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制】,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付TCP面向字节流
,实际上是TCP把数据看成一连串无结构的字节流
;UDP是面向报文的;UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
TCP首部开销20字节;UDP的首部开销小,只有8个字节
主要包括IP协议
。【传输层作为应用间数据传输的媒介,帮助实现应用到应用的通信,而实际的传输功能就交给下一层,也就是网络层(Internet Layer)
。】
IP 协议会将传输层的报文作为数据部分,再加上 IP 包头组装成 IP 报文
,如果 IP 报文大小超过 MTU(以太网中一般为 1500 字节)就会再次进行分片,得到一个即将发送到网络的 IP 报文。IP 协议的寻址作用是告诉我们去往下一个目的地该朝哪个方向走
】路由则是根据寻址结果也就是下一个目的地选择路径。寻址更像在导航,路由更像在操作方向盘。
路由器的端口都具有 MAC 地址,只接收与自身地址匹配的包,遇到不匹配的包则直接丢弃
。完成包接收操作之后,路由器就会去掉包开头的 MAC 头部。MAC 头部的作用就是将包送达路由器,其中的接收方 MAC 地址就是路由器端口的 MAC 地址。因此,当包到达路由器之后,MAC 头部的任务就完成了,于是 MAC 头部就会被丢弃。路由器会根据 MAC 头部后方的 IP 头部中的内容进行包的转发操作。【查询路由表判断转发目标。每个条目的子网掩码和 192.168.1.100 IP 做 & 与运算,得到的结果与对应条目的目标地址进行匹配,如果匹配就会作为候选转发目标,如果不匹配就继续与下个条目进行路由匹配。实在找不到匹配路由时,就会选择默认路由,路由表中子网掩码为 0.0.0.0 的记录表示「默认路由」
】后面的.0代表一个网络段或者范围而不是一个具体的地址哦,别忘记啦
】;子网掩码有两种表示方式【点分二进制方法表示,比如255.255.255.0。另一种就是CIDR表示方法,比如192.168.0.1/24,/24表示这个IP地址段中网络位占了24位,3个字节
】;判断两个IP地址是否属于同一个子网,把这俩分别跟子网掩码相与,如果与结果相同则表示这俩在一个子网中,路由器寻址就是按照这个原理算的
;子网划分/网络规划,来避免IP地址资源的浪费:【C类地址常用】PING其实就是向目的主机发送多个 ICMP 回送请求报文
,PING 主要的作用就是测试在两台主机之间能否建立连接,如果 PING 不通就无法建立连接
。
根据目的主机返回的回送报文的时间和成功响应的次数估算出数据包往返时间及丢包率
我们⼀般⽤ IP 地址给设备进⾏编号。IP地址由三部分组成:IP地址的类别+网络标识(网络位,NetWork ID)+主机标识(也叫主机位,Host ID)
。对于 IPv4 协议, IP 地址共 32 位,分成了四段(比如,192.168.100.1),每段是 8 位,一个字节。只有一个单纯的 IP 地址虽然做到了区分设备,但是寻址起来就特别麻烦,全世界那么多台设备,难道一个一个去匹配?这显然不科学。因此,需要将 IP 地址分成两种意义【需要配合子网掩码才能算出 IP 地址 的网络号和主机号,比如IP地址为10.100.122.0/24,/24表示子网掩码255.255.255.0
】:将 IP地址10.100.122.2 和 255.255.255.0 进行按位与运算,就可以得到网络号和主机号
网络号
,网络号负责标识该 IP 地址是属于哪个子网的
;
在寻址的过程中,先匹配到相同的网络号(表示要找到同一个子网),才会去找对应的主机。
主机号
,主机号负责标识同一子网下的不同主机
;相邻节点
的链路上传送帧。【MAC在两点传输 】
每⼀台设备的⽹卡都会有⼀个 MAC 地址
,它就是⽤来唯⼀标识设备的。路由器计算出了下⼀个⽬的地 IP 地址,再通过 ARP 协议找到该⽬的地的 MAC 地址
,这样就知道这个 IP 地址是哪个设备的了。路由器就是通过数据链路层来知道这个 ip 地址是属于哪个设备的,数据链路层主要为⽹络层提供链路级别传输的服务。
在路由表中找到相匹配的条目,然后把包发给 Gateway 列中的 IP 地址就可以了
。以太网就是一种在「局域网」内,把附近的设备连接起来,使它们之间可以进行通讯的技术。
同一局域网内,主机和主机通过交换机进行通信【因为交换机位于网络模型的第二层链路层,所以又叫2层设备,也叫二层交换机】
。在MAC层,交换机用来将网络包原样转发到目的地【发送了包之后目标设备会作出响应,只要返回了响应包,交换机就可以将它的地址写入 MAC 地址表,下次也就不需要把包发到所有端口了。所以此处的广播不会造成网络堵塞】路由器是基于 IP 设计的,俗称三层网络设备,路由器的各个端口都具有 MAC 地址和 IP 地址;而交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址
。在物理介质中传输,它主要是为数据链路层提供⼆进制传输的服务
。负责执行这一操作的是网卡,要控制网卡还需要靠网卡驱动程序
。网卡驱动获取网络包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。最后网卡会将包转为电信号,通过网线发送出去。物理地址:又叫MAC地址
,每一个厂商的每一块网卡都有,全球唯一。window中输入ipconfig /all,通常不可变。比如DC-4A-3E-E6-B9-2D:6组16进制数的方式表示逻辑地址:又叫IP地址【IP协议提供的一种统一的地址格式,用来标识网络中的主机,为互联网上每一个网络和主机都分配一个逻辑地址】,通常可变
。包含IPV4【4组十进制组成】和IPV6。因为MAC地址确实不好记忆,所以搞了一个好记的IP地址出来。更多的IP地址见上面网络层内的IP相关
互联网的本质就是一堆协议。程序员嫌OSI七层太麻烦了,所以把模型优化或者说简化为四层或者五层
TCP/IP其实就是由一些小的子网(子网相当于用集线器连接起来的几台计算机)通过路由器连接起来组成一个大的网络
,四层模型比较常见和实用
OSI 的协议实现起来过分复杂,而且运行效率很低
虽然整套的 OSI 国际标准都已经制定出来,但基于 TCP/IP 的互联网已经抢先在全球相当大的范围成功运行了
)OSI 的层次划分不太合理,有些功能在多个层次中重复出现
巨人的肩膀:
网络是怎样连接的
深入理解计算机网络
小林coding
javaGuide
腾讯云社区企鹅号 - PHP开源社区的老师的文章,关于应用系统之间数据传输的四种方式:应用系统之间数据传输有三个要素:传输方式【数据传输方式一般无非是:socket方式、ftp/文件共享服务器方式、数据库共享数据方式、message方式】,传输协议,数据格式
P妞酱儿老师关于应用系统间数据传输方式总结