个人学习分布式专题(四)分布式服务的基础之网络通信

网络通信

  4.1.1 协议

    4.1.1.1 TCP/IP(转自https://mp.weixin.qq.com/s/33FK5IuGq2da-O1xgS1AKA)

    4.1.1.2 UDP/IP

    4.1.1.3 Multicast

  4.1.2 IO(转自:https://www.cnblogs.com/zedosu/p/6666984.html#top)

    4.1.2.1 BIO

    4.1.2.2 NIO

    4.1.2.3 AIO


协议

TCP/IP

TCP/IP是一个协议簇,包括常见的HTTP协议,IP协议,TCP协议,DNS协议等都属于TCP/IP协议

TCP/IP模型:包含了一系列构成互联网基础的网络协议,是Internet的核心协议

基于TCP/IP的参考模型将协议分成四个层次,它们分别是链路层,网络层,传输层,应用层,下图表示TCP/IP模型和OSI模型各层的对照关系:

 

TCP/IP通信数据流:(以HTTP协议为例)

数据链路层

物理层负责比特流与物理设备电压高低,光的闪灭之间的互换。数据链路层负责将0,1序列划分为数据帧从一个节点传输到临近的另一个节点,这些节点是通过MAC来唯一标识的 

  

    • 封装成帧:把网络层数据报加头和尾,封装成帧,帧头中包括源MAC地址和目的MAC地址
    •   透明传输:零比特填充,转义字符
    •   可靠传输:在出错率很低的链路上很少用,但是无线链路WLAN会保证可靠传输
    •   差错检测(CRC):接收者检测错误,如果发现错误,丢弃该帧

网络层

 IP协议:是TCP/IP协议的核心,所有TCP,UDP,IMCP,IGMP的数据都是以IP数据格式传输。要注意的是,IP不是可靠的协议,IP协议没有提供一种数据未传达以后的处理机制;这被认为是上层协议TCP,UDP要做的事

IP地址:在数据链路层中我们一般通过MAC地址来识别不同的节点,而在IP层我们也要有个类似的地址标识,即IP地址

32位IP地址分为网络位和地址位,这样做可以减少路由器中路由表记录的数目,有了网络地址,就可以限定拥有相同网络地址的终端都在同一个范围内,那么路由表只需要维护一条这个网络地址的方向,就可以找到相应的这些终端了。

    • A类地址:10.0.0.0~10.255.255.255
    • B类地址:172.16.0.0~172.31.255.255 
    • C类地址:192.168.0.0~192.168.255.255

IP协议头:

 

这里只介绍:八位的TTL字段。这个字段规定该数据包在穿过多少个路由之后才会被抛弃。某个IP数据包每穿过一个路由器,该数据包的TTL数值就会减少1,当该数据包的TTL成为零,它就会被自动抛弃。
这个字段的最大值也就是255,也就是说一个协议包也就在路由器里面穿行255次就会被抛弃了,根据系统的不同,这个数字也不一样,一般是32或者是64。

ARP及RARP协议

ARP(地址解析)协议是根据IP地址获取MAC地址的一种协议;是一种解析协议,本来主机是完全不知道这个IP对应的是哪个主机的哪个接口,当主机要发送一个IP包的时候,会先检查一下自己的ARP高速缓存;如果查询的IP-MAC值不存在,那么主机就向网络发送一个ARP协议广播包,这个广播包里面就有待查询的IP地址,而接收到这份广播包的所有主机就会查询自己IP地址,若某主机发现自己符合条件,就准备好一个包含自己MAC地址的ARP包传送给发送ARP广播的主机;而广播主机拿到ARP包后会更新自己的ARP缓存,发送广播的主机就会用新的ARP缓存数据准备好数据链路层的数据包发送工作。

RARP与之相反。

ICMP(网络控制报文)协议:不是高层协议,是IP层的协议,它是负责保证数据送达的工作的模块。

当传送IP数据包发生错误,比如主机不可达,路由不可达等,ICMP协议会将错误信息封包,然后传送回主机,给主机一个处理错误的机会。

PING

ping是ICMP的一个应用,是TCP/IP协议的一部分,它利用ICMP协议包来侦测另一个主机是否可达,原理是用类型码为0的ICMP发请求,受到请求的主机则用类型码为8的ICMP回应

TCP/UDP

TCP/UDP都是传输层协议,但是两者具有不同的特性,同时也具有不同的应用场景,下面是对比分析:

面向报文的传输方式是应用层交给UDP多长的报文,UDP就照样发送,因此,应用程序必须选择合适大小的报文。若报文太长,则IP层需要分片,降低效率。若太多,会是IP太小

面向字节流时,虽然应用程序和TCP的交互是一次一个数据块,但TCP把应用程序看成是一连串的无结构的字节流。TCP有一个缓冲,当应用程序传送的数据块太长,TCP就可以把它划分短再传送

TCP和UDP协议的一些应用:

DNS

DNS(域名系统):因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网。通过主机名,最终得到该主机名对于的IP地址的过程叫做域名解析(或主机名解析)。DNS协议运行在UDP协议之上,使用端口号53


TCP连接的建立与终止

 三次握手

TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换 TCP窗口大小信息。

第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,SequenceNumber为x;然后客户端进入SYN_SEND状态,等待服务器确认

第二次握手:服务器接收到SYN报文段进行确认,设置AcknowledgmentNumber为x+1;同时自己还要发送SYN请求,将SYN置为1,SequenceNumber为y;服务端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态

第三次握手: 客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

为什么要三次握手:为了防止已失效的连接请求报文突然又传送到了服务端,因而产生错误

 四次挥手:当数据传送完毕,断开TCP连接

第一次分手: 主机1(可以使客户端,也可以是服务器端),设置Sequence Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次分手: 主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;

第三次分手: 主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;

第四次分手: 主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

为什么要四次分手:TCP协议是一种面向连接的,可靠的,基于字节流的运输层通信协议。TCP是全双工模式,这就意味着当主机1发出FIN报文段时,只是表示主机1没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是这时主机1还是可以接收来自主机2的数据;当主机2返回ACK报文时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

 MUlticast:组播


IO 

BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。 

工作情况:在while循环中服务端会调用accept方法等待接收客户端的连接请求,一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成。 

如果BIO要能够同时处理多个客户端请求,就必须使用多线程,即每次accept阻塞等待来自客户端请求,一旦受到连接请求就建立通信套接字同时开启一个新的线程来处理这个套接字的数据读写请求,然后立刻又继续accept等待其他客户端连接请求,即为每一个客

连接请求都创建一个线程来单独处理

缺点:虽然此时服务器具备了高并发能力,即能够同时处理多个客户端请求了,但是却带来了一个问题,随着开启的线程数目增多,将会消耗过多的内存资源,导致服务器变慢甚至崩溃,NIO可以一定程度解决这个问题。

应用场景:适用于连接数目比较小且固定的场景,这种方式对服务器资源要求比较高,并发局限于应用中。

NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。采用了事件驱动的思想来实现了一个多路转换器;采用了Reactor模式。

  NIO与BIO最大的区别:就是只需要开启一个线程就可以处理来自多个客户端的IO事件,NIO采用多路复用器,可以监听来自多个客户端的IO事件:

工作情况:

A. 若服务端监听到客户端连接请求,便为其建立通信套接字(java中就是通道),然后返回继续监听,若同时有多个客户端连接请求到来也可以全部收到,依次为它们都建立通信套接字。 

B. 若服务端监听到来自已经创建了通信套接字的客户端发送来的数据,就会调用对应接口处理接收到的数据,若同时有多个客户端发来数据也可以依次进行处理。 

C. 监听多个客户端的连接请求和接收数据请求同时还能监听自己时候有数据要发送。 

总之就是在一个线程中就可以调用多路复用接口(java中是select)阻塞同时监听来自多个客户端的IO请求,一旦有收到IO请求就调用对应函数处理。

适用场景:适合处理连接数目特别多,但是连接比较短(轻操作)的场景,Jetty,Mina,ZooKeeper等都是基于java nio实现。它的特点是要不断主动地去询问数据有没有处理完,一般只适用于连接数目较大但连接时间短的应用,如聊天应用等。

三大核心组件:Channels,Buffers,Selectors

缓冲区Buffer一个数据对象;在JavaNIO中,任何时候访问,读取NIO中的数据,都需要通过缓冲区进行操作。NIO最常用的缓冲区是ByteBuffer,每个Java基本类型都对应一种Buffer

通道Channel:网络数据通过Channel读取与写入,必须结合Buffer使用;主要用于I/O操作的连接,主要的实现类:

  FileChannel:一个用来写读映射和操作文件的通道

  DatagramChannel:能通过UDP读写网络中的数据

  SocketChannel:能通过TCP读写网络中的数据

  ServerSocketChannel:可以监听新进来的TCP连接,像web服务器那样,对每个新进来的连接都会创建一个SocketChannel

多路复用器Selector

它提供选择已就绪任务的能力,是Java NIO编程的基础;Selector会不断轮询注册其上的Channel,如果某个Channel上面发生了读写事件,这个Channel就处于就绪的状态,会被selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的IO操作

  Selector允许一个线程处理多个Channel,也就是说只要一个线程负责Selector的轮询,就可以处理成千上万个Channel

  

 

AIO(NIO.2):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。 jdk1.7开始应用,叫做异步不阻塞的IO。AIO引入异常通道的概念,采用了Proactor模式,简化了程序编写,一个有

效的请求才启动一个线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间长的应用。

三种IO对比,如图所示:

参考

  • Java NIO 系列教程

  • Netty 权威指南(第2版)

  •  http://baijiahao.baidu.com/s?id=1573998393898438&wfr=spider&for=pc
  •  http://cmsblogs.com/ 『chenssy』

 

猜你喜欢

转载自www.cnblogs.com/hangzhi/p/9105448.html