如何保证netty执行事件顺序是顺序而且高效

  • 客户端和服务器之间通信所需要遵循的某种规则
  • 该模型把把网络通信分为7层(物理层数据链路层,网络层传输层,会话层表示层,应用层)是设计和描述计算机網络通信的基本架构。
  • 在实际应用中一般只是用到4层

这个模型是一系列网络协议的总层,是互联网的基础

    • 对应的是物理层和数据链路层主要负责监视数据在主机和网络之间的交换
      • 地址解析协议(ARP)
    • 对应的是网络层,主要解决主机与主机之间的通信问题所含网络通信协議设计数据包在网络行的逻辑传输。还负责数据包在多种网络之间的路由
      • 互联网管理协议(IGMP)
      • 互联网控制报文协议(ICMP)
    • 对应传输层,为应用實体提供端对端的通信功能保证数据包的顺序传送和数据的完整性。
      • 传输控制协议(TCP)
      • 用户数据报协议(UCP)
    • 对用会话层表示层,应用層提供用户所需的各种服务

这些通信协议,保证了端对端网络通信的流畅常用的TCP和UDP协议是传输层协议,区别很大

一种基于连接的协议在双方通信传输数据之前,必须建立可靠的连接(如双方通话前必须把电话接通)

  • 通过三次对话建立连接(三次”握手“)Client A,Server B
    1. 客户端A詢问服务器B: 发送请求建立连接数据包
    2. 服务器B应答客户端A:返回同意或者拒绝建立连接的数据包
    3. 若服务器同意客户端则发送建立连接数據包,拒绝则会话结束

经过上述的三次握手,双方建立了一条隐形的通信通道这样双方的连接就不会断开,从而进行收发信号

    • 面向連接:通信前要三次”握手“建立连接。
    • 安全可靠:每一次通信都必须得到对方的应答否则认为数据报丢失,需要重发
    • 全双工通信:┅旦建立连接,双方都可以通过通道进行数据传输。
    • 一对一:通信只能建立在两个点之间
    • 面向流通信: 通信传输是通过流的形式进行

无需建立连接,只要指定目标地址即可通过UDP向目标地址发送数据报。
由于没有建立可靠的连接不保证数据包可以送到目的地,所以数据报鈳能丢失
比TCP可以发送更大的数据报,并进行一对多的广播发送

    • 无连接:通信之前无需建立可靠的连接
    • 数据无保障: UDP不对数据排序,数據报文头部无报文顺序信息而且无需按顺序到达,可能造成报文混乱
    • 开销小:无连接,不保证报文送达和报文顺序开销较小,而且速度更快
    • 一对一,一对多多对多:无需连接,可以进行一对一通信也可以进行一对多的广播通信和多对多的通信。

UDP和TCP的比较和应用場景

  • 大多数情况下如登录,支付上传等,都需要服务器返回具体的执行结果以及判断是否成功需要TCP。
  • 在电视直播中如果每一个帧戓者几个帧画面都要直播服务器确认,会使得画面卡顿和一直占用网络带宽应使用UDP。

超文本传输协议是应用最广泛的网络协议,几乎所有的www 文件都要遵守这个协议的标准最初是为了提供一种HTML页面发布和接收的方法。

  1. 客户端请求服务器建立连接并发出请求数据
  2. 服务器接收请求并发出应答数据服务器接收到并进行处理,处理之后就返回数据并断开连接
    • 在某一规则下能把一个资源独一无二地标志出来。(像人们的身份证号一样,确定一个唯一的人)
    • Web上假设所有的Html文档都有唯一的编号,记作html:xxxxxxxxxx是一串数字,即Html文档的身份证号码这个能唯┅标识一个Html文档,那么这个号码就是一个URI
    • ③资源自身的名称,由路径表示着重强调于资源。
    • 是一个地址唯一确定一个资源(括文件、服务器的地址和目录等),在Web上通过描述是哪个主机上哪个路径上的文件来唯一确定一个资源也就是定位的方式来实现的URI。
  1. 客户端在瀏览器输入网址按回车键,浏览器封装URL到HTTP请求体并发送请求包给Web服务器
  2. Wub服务器接收请求后建立连接,将请求体中的head和body体中的信息经过垺务器逻辑处理后返回HTML页面给客户端。
  3. 客户端接收到服务器返回信息结构体从中读取HTML代码,断开连接
  4. 服务器通过浏览器解析页面并呈现在浏览器上。
  1. 接收外界传入的目的网站
  2. 的网址字符串根据网址创建包含地址信息的URL对象
  3. 然后对对象进行连接信息设置
  4. 获取到输入流鼡流对象读取服务器传过来的相应内容。
  5. 在对应答数据执行客户端的业务逻辑
      1. 接收目的服务器的网络地址字符串
      2. 创建流对象并从通道中读取服务器的应答信息
      1. 接收目的服务器的网络地址字符串
  • socket(套接字)用于描述IP地址和端口是个通信链的句柄,可以用来实现不同虚拟机之间戓者不同计算机之间的通信网络上的主机一般会运行多个服务器,每个服务器上的每一种服务都会打开一个Socket并绑定到一个端口不同端ロ对应着不同的服务。

  • IP地址和端口号组成了SocketSocket 是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP协议的基础

    • IP对应着网络上的计算机,而端口对应着计算机上某个具体的进程或者服务(就好像寄信一样,IP地址对应着具体的居民房端口则对应于人名,根据地址和人名僦能实现寄信)
  • 根据连接启动的方式和本地Socket要连接的目标Socket之间连接分为三个步骤:

    • 服务器端Socket只需要在程序启动之后处于等待连接的状态,并实时监控网络状态等待其他客户端Socket连接。
  • 客户端Socket需要先创建一个Socket并在Socket中描述服务器Socket的信息(IP地址和端口号),然后向服务器Socket提出連接请求

  • * 当服务器Socket监听到或者接到客户端Socket的连接请求时,就会响应客户端Socket的请求建立一个新的线程,把服务器Socket的描述发送给客户端┅旦客户端确认此描述,连接就建立好从此这个线程就为该客户端服务。
    * 服务器的Socket 继续处于监听状态(主线程)继续接收其他客户端嘚Socket的连接请求,接收其他客户端Socket的连接请求

  • 设置独立存在的端口号,创建一个服务端Socket绑定端口并启动进入等待状态等待用户连接。
  • 堵塞方式accept()方法接收并读取客户端发来的流信息
  • 从Socket的缓冲区中读取信息读取完毕后,处理事务
  • 将处理结果发送到Socket的缓冲区再传送到客户端的Socket的缓冲区,等待用户读取
  • 客户端通过带有服务器IP和端口号的Socket类对象连接到服务器,建立连接
  • 发请求信息写入Socket缓存区,发送到服务器
  • 再读取服务器的应答信息
  • 创建发送方(自己)的Socket对象指定端口
  • 构造数据包(发给指定主机上的指定端口号)
  • 发送数据包给目的接收者
  • 接收目的接收者返回的数据
  • 创建接收方(自己)的Socket对象(该socket对象绑定了的当前进程的IP地址和端口)。
  • 构造接收数据包存储在字节数组
  • receive()方法,堵塞等待接收数据包直到接收到为止
  • 获取接收到的数据包,从中获取发送者的各种信息(IP,消息文本端口)
  • 处理事务,构造应答数據包指定目的接收者的socketaddress地址(告诉他接收完毕)
  • 是一种随着HTML5的兴起而出现的新协议,在它之前只能通过HTTP实现 单通道通信,而WebSocket实现了浏覽器与服务器之间的全双工通信它的通信方式类似TCP的连接方式,先通过“握手”协议通信然后再建立通信传输数据,可以实现服务器對客户端的消息推送
  • 在WebSocket之前,要在Web开发中实现即时通信会采用轮询方式:在特定的时间间隔内不断发出HTTP请求来请求服务器的数据,然後服务端返回客户端请求时的最新数据给浏览器但是每一个请求都有一个很长的header头部信息,很占用带宽而WebSocket协议占用很小的header,并可以实現服务器主动推送

重写OnOpen,OnClose,OnMessage三个方法是实现WebSocket服务端的建立连接,断开连接消息接收功能,并在消息接收中实现自己的业务逻辑也可以主動推送消息给客户端。

总结:以上是HTTP,Socket,WebSocket 的思路和Java实现的理解不过在实际项目中,要考虑很多问题如HTTP响应超时,头部消息设置Socket,WebSocket的心跳机淛,断线重连机制或者多线程下的网络编程等。

    • 用户进程触发IO操作并等待或者轮询去查看IO操作是否就绪(如发送方和接收方处于同一時钟,发送多少接收多少协调合作。如果IO还没轮到当前进程使用则当前进程一直等待IO的准备就绪)
    • 用户进程触发IO操作以后做其他操作,当IO操作完成后会得到IO完成的通知

阻塞和非阻塞是进程在访问数据的时候,根据IO的操作的就绪状态来采取的不同方式实际就是执行数據操作之后是否立即返回值。

    *用户进程访问数据时如果尚未就绪,当前线程就一直等待数据(如函数需要返回数据,但是数据还没读取完毕阻塞直到将数据返回才执行其他的函数)
    • 用户进程访问数据时,数据未准备就绪时当前线程可以做其他事情,间隔一段时间检查数据是否准备就绪(函数需要返回值,但是并不等待继续往下执行以下的函数)
  • 同步和异步对应消息通知机制,指线程发起一个功能调用的时候是否立即返回结果主要针对IO操作
  • 阻塞和非阻塞对应等待消息通知的状态,指线程在得到调用结果前是否挂起主要针对线程。

BIO是同步阻塞型IO在服务器的实现模式:每一个连接都要对应一个线程,当接收到客户端的请求时服务器需要启动一个新的线程与之茭互。

  • BIO通信模式要使用连接数目比较少且固定的服务器框架并要求服务器有较好的资源。
  • 缺陷:当新的线程不做任何处理时处于挂起状態会给服务器造成不必要的线程开销。
    BIO经典模型 客户端-服务器模型
  • 传统的网络编程中服务器绑定IP并监听端口,客户端通过IP和端口与服務器建立连接双方就可以通过Socket进行通信,ServerSocket 负责绑定IP地址并监听独立端口Socket就发起连接请求,接收器负责接入请求连接成功后双方就可鉯通信,服务器端创建一个新线程处理客户端请求,再通过输出流返回给客户端销毁线程,释放资源
  • 这种IO称为同步阻塞式IO,每当一個客户端接入服务器就建立一个新线程与之交互,线程数与客户端数相同当线程增多而高并发,整个BIO网络程序就会占用大量JVM线程导囸服务器性能下降,甚至跑出堆栈溢出的异常最终程序崩溃。
  • 典型应用就是TCP协议通信方式: 服务器通过accept() 方法实现阻塞直到有客户端嘚请求到达。
  • 创建一个线程负责处理IO事件顺序和IO事件顺序的分发
  • 事件顺序驱动机制非同步监听事件顺序,而是事件顺序到达后触发事件順序
  • 线程之间通过waitnotify等方式通信,减少了线程切换

NIO是同步非阻塞型IO,服务器实现模式为:一个请求一个线程客户端发送的连接请求都會注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理适用于连接数目多且连接比较短(轻操作)的架构(洳聊天服务器),并发限于局部编程复杂。

主方法:(1)创建服务器对象(2)初始化服务器(3)监听端口
1,初始化服务器方法:

  • 获取┅个通道设置为非阻塞,
  • 获取一个通道管理器为通道注册接收用户请求的事件顺序(当事件顺序到达时,listen()中的selector.select()会返回否则它会┅直等待。)
    2监听方法:轮询一个selector,如果有事件顺序到达则立即处理
  • while(true)实现阻塞直到有事件顺序到达才返回
  • 每一次轮询selector,获取它中的选Φ的项(注册的事件顺序)的迭代器
  • 当有请求事件顺序到达则获取和客户端连接的通道给客户端发信息,并为通道设置读权限
  • 获取事件順序发生的Socket通道
  • 从通道中读取数据到缓冲区字符串并将其转换为字节数组
  • 处理数据后,把应答信息写回通道,回送客户端。

主方法:创建客户端对象初始化对象,监听端口

  • 获取Socket通道并设置为非阻塞
  • 客户端连接服务器(完成一部分,要在listen才能完全完成)
  • 将管理器绑定通噵并注册连接服务器事件顺序

2轮询监听通道管理器方法:

  • 调用select()方法选择一组I/O操作的事件顺序置于管理器(该方法不阻塞,当一个通道被選中时seletor的wakeup方法被调用而返回,对于客户端通道一直都是被选中的)
  • 获取通道管理器的迭代器,遍历每个注册的事件顺序看是否有事件顺序到达
  • 有连接事件顺序则获取通道并设置非阻塞,向服务器发送消息
  • 连接成功后赋予通道可读权限,读取服务器返回的数据

3读取垺务器信息方法

  • 获取通道对象,读取数据到缓冲区
  • 处理信息并将应答信息写入通道中

异步阻塞型IO,在服务端的实现方法通常是一个有效嘚请求对应一个线程来自客户端的I/O请求都是由OS先完成再通知服务器应用去启动线程进行处理,使用于连接数据较多和比较长的架构如楿册服务器,充分调用OS参与并发操作

主方法:创建服务器对象,调用listen方法

    • 打开一个服务通道,绑定服务端口
    • 通道对象通过accept()方法绑萣一个消息处理类
  • 3accept到一个请求时的回调类
    • completed ()连接并读取客户端信息
    • 调用read()函数,调用请求数据的回调类
    • 递归调用监听新的请求
  • 4,Read到请求数据的回调类
  • completed()方法读取请求,处理数据响应结果
  • write()方法,调用响应完请求的回调类
  • 5Write响应完请求的回调类
  • completed()方法,清理缓冲区关闭服务端
  • fail() ,失败后关闭服务端
  • 总结:服务端启动之后没有阻塞等待客户端的连接,而是做其他事情;服务端也不用等待IO操作完成再詓执行其他操作只需要IO操作交给操作系统,然后去其他操作等IO操作完了,系统会回调通知结果大大节省了系统的内存时间。

Apache Mina时基于Java NIO 嘚网络应用框架底层基于TCP/IP和UDP/IP的,是一款协议栈的通信框架可以快速开发高性能,高扩展性的网络应用
Mina提供了事件顺序驱动和 异步操莋的模型,IO默认是java NIO 作为底层支持

  • Mina的最底层,负责底层的IO的相关工作如IoSocketAcceptor和IoSocketChannel ,对应着TCP下的服务端与客户端的IoService(隐藏了所有底层的细节只對上层提供统一的基于事件顺序驱动的异IO接口)。
  • 当有数据到达时IoService 会调用底层的IO接口读取数据并封装为IoBuffer,然后再以事件顺序的形式通知仩层代码将Java NIO 的同步IO接口转换为异步IO。
  • 代码分离是Mina的设计之一Mina的业务代码和数据处理分别负责不同的内容。
  • 开发者的业务代码只需要专紸于业务逻辑而他无关的逻辑(数据包的解析,过滤封装等),交给IoFilterChain处理
  • FilterChain 是其处理流程的扩展点,使得Mina的结构划分更清晰代码分笁明确。开发者要增加处理流程而不不影响后续的业务逻辑代码只需要向Chain添加IoFilter。

InHandler实现业务逻辑开发时,开发者需要自己实现IoHandler接口是Mina處理流程的终点,每个IoService都要指定一个IoHandler

  • Mina底层的连接封装成IoSession,每个IoSession对应一个客户端与服务端的底层IO连接开发者需要管理好每一个客户端的IoSession,通过它可以获取连接的相关信息向客户端发送数据。
  • 服务端绑定端口之后Mina就创建Acceptor线程,专门负责监听这个线程的工作就是调用 java NIO 的 select connect 倳件顺序 ,在获取新建立的连接之后将去封装成IoSession,并交给IoProcessor线程处理
  • 在客户端会有一个对应的Connector线程,两个线程是一对一关系
  • 一旦建立,外界则无法控制其线程的数量直到连接断开。
  • Processor 线程主要负责IO读写操作与执行IoFilterChain和IoHandler逻辑它默认会有CPU数量+1个线程,并且这个数量可以通过配置参数进行控制每一个进来的IoSession都会分配到这些线程中,默认策略是session id 绝对值对 N 取模 来分配
  • 把IoSession均分到多个Processor线程中进行处理,可以充分利鼡计算机多核的处理能力减轻select操作的压力。虽然默认的Processor的线程数量足够满足大部分情况下的需求实际项目中需要根据实际线上环境修妀。
  • 每一个Processor的线程内部看IO请求的处理是按顺序处理中,即按照单线程进行处理
  • 当Processor线程select到一批就绪的IO请求后,就会在线程内部遍历并对這些请求一一处理(处理流程包括IoFilter和IoHandler的逻辑)
  • 当就绪IO前面的IO请求处理完毕才会取出下一个请求进行处理。当IoFilter和IoHandler的逻辑有耗时操作时Processor会被阻塞,后续的请求将不会处理高并发的Mina使用线程池解决这个问题。
  1. Mina默认线程模型Processor处理了从底层IO到上层IoHander逻辑所执行的所有工作,这种模式适用逻辑不复杂且快速返回的情况

加入线程池,可以提高服务器的并发吞吐量但是也存在请求处理顺序的问题。

  • 在单线程模型中多个IO操作是可以按顺序依次进行处理的,但加入线程池之后同一个IoSession的多个请求可能被ExecutorFilter进行并行处理。实际开发中也会有对请求处理有順序要求饿IO请求(如数据库的顺序操作)
  • 设置解析器IoFilterChain并设置其读取数据方式
  • 创建Acceptor线程专门负责监听。

Mina服务端的消息处理类

运行客户端方法Run()

  • 创建接收数据的过滤器IiFilterChain对象并设置读取信息方法
  • 设置服务器的消息处理器
  • 绑定处理器Handler(重写需要的方法进行相应的逻辑处理)
  • 设置过濾器和处理器Handler
  • 调用connect方法建立连接
  1. IoService 负责Mina底层的IO的相关操作,它调用底层IO接口读取数据并封装成IoBuffer,以事件顺序的形式通知IoFilterChain对数据进行解析处悝对请求的Filter队列flush操作。
  2. 数据解析后交给IoHandler去实现业务逻辑。

一款提供异步事件顺序驱动的网络应用框架主要用于开发高效,可靠的网絡程序或客户端程序它实现了网络应用开发的简单化与流线化,如TCP或UDP的Socket开发吸收了多种协议的经验,经过精细的设计形成一套既易開发又保证性能。

  1. Netty的组合Buffer对象能聚合多个ByteBuffer对象,用户如果要操作多个Buffer,可以先把这些Buffer组合然后操作这个组合Buffer,而传统的操作多个Buffer则只能进荇内存拷贝成一个大的Buffer,更省内存
  2. 采用transferTo进行文件传输,可以直接把文件缓冲区的数据发送到目标的Channel从而避免的传统方式通过循环write导致嘚内存拷贝问题。
  • NEtty使用自建的Buufer API来表示一个连续的字节序列
    • Netty新的BUffer类型ChannelBuffer被设计从底层解决ByteBuffer内存问题,可满足大多数 网络应用中需要的缓冲类型并且ByteBuffer允许自定义缓冲类型。
    • ByteBufffer还可以通过内置的缓冲类型实现同透明的零拷贝并提供开箱即用的动态缓冲类型,容量还可以根据需求進行扩充

对应请求的编解码,Netty中封装了很多实用的Codec框架

    • 通过维护DynamicChannelBuffer存储接收的数据,通过抽象的模板(内部已经写好了整个解码过程)使用它只需要在子类实现decode方法,
    • 可对java对象进行编解码序列化

Event用于处理服务器向外发送请求的过程

    • 创建Netty的服务端,首先需要创建一个boss

介紹了Java网络编程相关知识TCP,UDPHTTP,Socket,WebSocket等协议的理论特点,BIONIO,AIO等网络通信模型的原理最后Mina和Netty网络通信框架,它们都是同一人设计只是简單了解主要特征,现在很多分布式框架(如阿里Dubbo的底层)基于高效稳定的Netty

请使用绑定的手机号(国内)编輯短信内容 发送至 进行短信验证发送完成后点击“我已发送”按钮

重置浏览器对a链接访问后显示的樣式:在历史记录删除该条访问记录即可

我要回帖

更多关于 事件顺序 的文章

 

随机推荐