一个 http 请求,在整个网络中的请求过程
当应用程序用 TCP 传送数据时,数据被送入协议栈中, 然后逐个通过每一层直到被当作一串比特流送入网络。其 中每一层对收到的数据都要增加一些首部信息
当目的主机收到一个以太网数据帧时,数据就开始从协议 栈中由底向上升,同时去掉各层协议加上的报文首部。每层协议盒都要去检查报文首部中的协议标识,以确定接收 数据的上层协议。这个过程称作分用
为什么有了 MAC 层还要走 IP 层呢?
mac 地址就好像个人的身份证号,人的身份证号和人户口 所在的城市,出生的日期有关,但是和人所在的位置没有 关系,人是会移动的,知道一个人的身份证号,并不能找 到它这个人,mac 地址类似,它是和设备的生产者,批 次,日期之类的关联起来,知道一个设备的 mac,并不能 在网络中将数据发送给它,除非它和发送方的在同一个网 络内。所以要实现机器之间的通信,还需要有 ip 地址的 概念,ip 地址表达的是当前机器在网络中的位置,类似于 城市名+道路号+门牌号的概念。通过 ip 层的寻址,我们 能知道按何种路径在全世界任意两台 Internet 上的的机器 间传输数据。
IP 协议与 TCP/UDP 协议
什么是协议
协议相当于两个需要通过网络通信的程序达成的一种约定, 它规定了报文的交换方式和包含的意义。比如(HTTP)为 了解决在服务器之间传递超文本对象的问题,这些超文本 对象在服务器中创建和存储,并由 Web 浏览器进行可视 化,完成用户对远程内容的感知和体验
什么是 IP 协议
T C P 和 U D P 是两种最为著名的传输层协议,他们都是 使用 I P 作为网络层协议。IP 协议提供了一组数据报文服 务,每组分组报文都是由网络独立处理和分发,就像寄送 快递包裹一样,为了实现这个功能,每个 IP 报文必须包 含一个目的地址的字段;就像我们寄送快递都需要写明收 件人信息,但是和我们寄送快递一样,也可能会出现包裹 丢失问题,所以 IP 协议只是一个“尽力而为”的协议,在网 络传输过程中,可能会发生报文丢失、报文顺序打乱,重 复发送的情况。IP 协议层之上的传输层,提供了两种可以 选择的协议,TCP、UPD。这两种协议都是建立在 IP 层所 提供的服务基础上,根据应用程序的不同需求选择不同方 式的传输;
TCP/IP
TCP 协议能够检测和恢复 IP 层提供的主机到主机的通信 中可能发生的报文丢失、重复及其他错误。TCP 提供了一 个可信赖的字节流通道,这样应用程序就不需要考虑这些 问题。同时,TCP 协议是一种面向连接的协议,在使用 TCP 进行通信之前,两个应用程序之间需要建立一个 TCP 连接, 而这个连接又涉及到两台电脑需要完成握手消息的交换。
UDP/IP
UDP 协议不会对 IP 层产生的错误进行修复,而是简单的 扩展了 IP 协议“尽力而为”的数据报文服务,使他能够在应 用程序之间工作,而不是在主机之间工作,因此使用 UDP 协议必须要考虑到报文丢失,顺序混乱的问题
TCP 是如何做到可靠传输的?
建立可靠的链接
由于 TCP 协议是一种可信的传输协议,所以在传输之 前,需要通过三次握手建立一个连接,所谓的三次握手, 就是在建立 TCP 链接时,需要客户端和服务端总共发送 3 个包来确认连接的建立
TCP 四次挥手协议
四次挥手表示 TCP 断开连接的时候,需要客户端和服务端 总共发送 4 个包以确认连接的断开;客户端或服务器均可 主动发起挥手动作(因为 TCP 是一个全双工协议),在 socket 编程中,任何一方执行 close() 操作即可产生挥手 操作。
tips:为什么连接的时候是三次握手,关闭的时候却是四次握手?
三次握手是因为因为当 Server 端收到 Client 端的 SYN 连 接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是关闭连 接时,当 Server 端收到 FIN 报文时,很可能并不会立即 关闭 SOCKET(因为可能还有消息没处理完),所以只能 先回复一个 ACK 报文,告诉 Client 端,"你发的 FIN 报文 我收到了"。只有等到我 Server 端所有的报文都发送完 了,我才能发送 FIN 报文,因此不能一起发送。故需要四步握手。
数据传输过程的流量控制和确认机制
建立可靠连接以后,就开始进行数据传输了。在通信过程 中,最重要的是数据包,也就是协议传输的数据。如果数据的传送与接收过程当中出现收方来不及接收的情况,这时就需要对发方进行控制以免数据丢失。利用滑动窗口机制可以很方便的在 TCP 连接上实现对发送方的流量控制。TCP 的窗口单位是字节,不是报文段,发送方的发送窗口不能超过接收方给出的接收窗口的数值。
滑动窗口协议
滑动窗口(Sliding window)是一种流量控制技术。早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发不了数据,所以就有了滑动窗口机制来解决此问题;发送和接受方都会维护一个数据 帧的序列,这个序列被称作窗口
简单解释下,发送和接受方都会维护一个数据帧的序列, 这个序列被称作窗口。发送方的窗口大小由接受方确定, 目的在于控制发送速度,以免接受方的缓存不够大,而导 致溢出,同时控制流量也可以避免网络拥塞。下面图中的 4,5,6 号数据帧已经被发送出去,但是未收到关联的 ACK,7,8,9 帧则是等待发送。可以看出发送端的窗口大 小为 6,这是由接受端告知的。此时如果发送端收到 4 号 ACK,则窗口的左边缘向右收缩,窗口的右边缘则向右扩 展,此时窗口就向前“滑动了”,即数据帧 10 也可以被发 送。
通信的性能问题?
正常的通信过程如下(BIO)
我们发现 TCP 响应服务器一次只能处理一个客户端请 求,当一个客户端向一个已经被其他客户端占用的服务器 发送连接请求时,虽然在连接建立后可以向服务端发送数 据,但是在服务端处理完之前的请求之前,却不会对新的 客户端做出响应,这种类型的服务器称为“迭代服务器”。 迭代服务器是按照顺序处理客户端请求,也就是服务端必 须要处理完前一个请求才能对下一个客户端的请求进行响 应。但是在实际应用中,我们不能接收这样的处理方式。 所以我们需要一种方法可以独立处理每一个连接,并且他 们之间不会相互干扰。而 Java 提供的多线程技术刚好满 足这个需求,这个机制使得服务器能够方便处理多个客户端的请求。
什么是NIO、BIO、AIO?他们的区别?
一、同步阻塞I/O(BIO):
同步阻塞I/O,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制来改善。BIO方式适用于连接数目比较小且固定的架构,这种方式对服务端资源要求比较高,并发局限于应用中,在jdk1.4以前是唯一的io现在,但程序直观简单易理解
二、同步非阻塞I/O(NIO):
同步非阻塞I/O,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,jdk1,4开始支持
三、异步非阻塞I/O(AIO):
异步非阻塞I/O,服务器实现模式为一个有效请求一个线程,客户端的IO请求都是由操作系统先完成了再通知服务器用其启动线程进行处理。AIO方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,jdk1.7开始支持。
如果你想吃一份宫保鸡丁盖饭:
同步阻塞:你到饭馆点餐,然后在那等着,还要一边喊:好了没啊!
同步非阻塞:在饭馆点完餐,就去遛狗了。不过溜一会儿,就回饭馆喊一声:好了没啊!
异步阻塞:遛狗的时候,接到饭馆电话,说饭做好了,让您亲自去拿。
异步非阻塞:饭馆打电话说,我们知道您的位置,一会给你送过来,安心遛狗就可以了。
什么是多路复用?
多路复用器 Selector,是 NIO 的基础,多路复用器提供选择已经就绪的任务的能力,简单来说,Selector 会不断轮询注册上的 Channel,如果某个 Channel 上面有新的 TCP 连接接入、读、写事件,这个 Channel 就处于就绪状态,会被 Selector 轮询出来,然后通过 SelectionKey 可以获取就绪的 Channel 进行 I/O 操作;一个多路复用器可以同时轮询多个 Channel。通过这个机制可以接入成千上万的客户端。