山东聊城针灸培训:Netty编程的一些笔记

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 01:16:57
Netty的一些笔记 


  • 1. 仍然要说明一点,netty仍然是一个nio,其开发者与mina是同一个人,可以认为时mina的升级版和改进版吧。
  • 2. 其实对nio框架的编程的,我已经不是太热衷,毕竟就是使用一个工具而已,因为熟悉了nio的编程模式,发现这些框架都是千篇一律,只不过看看谁封装得好,效率更高而已。其实自己实现一个nio框架也未尝是件难事,但是我相信,写到最后,你会发现你写的和这些框架也肯定类似,重复造轮子不说,估计还没有别人写得好。
  • 3. 写这篇博客的目的,如果我以后要用netty再编程时,使用api更方便些,方便来查找看看。


1. ServerSocket的bind流程 

(1) ServerSocketChannel.open()-->之后fireChannelOpen,向上流(一般处理ServerSocket的配置信息); 
(2)fireChannelOpen中调用chanel的bind方法-->bind事件(向下流)(,socket.socket().bind处理具体的绑定工作,之后触发fireChannelBound;若是执行 
socket.close(),则触发fireChannelUnbound,fireChannelClosed,向上流 

2. 处理Socket 
(1)创建一个新的ChannelPipeline对象与之关联; 
(2)创建实例NioAcceptedSocketChannel,触发fireChannelOpen,fireChannelBound,fireChannelConnected事件 
(3)注册到NioWorker 
(4)fireChannelBound,fireChannelConnected 


3. buffer说明 

(1) 用两个变量维持buffer的可读,可写的内容 
      +-------------------+------------------+------------------+ 
      | discardable bytes |  readable bytes  |  writable bytes  | 
      |                   |     (CONTENT)    |                  | 
      +-------------------+------------------+------------------+ 
      |                   |                  |                  | 
      0      <=      readerIndex   <=   writerIndex    <=    capacity 
初始值: 
readerIndex=0; 
wirterIndex=0; 

可以读的大小: readerIndex---(writerIndex - 1), 都是包含 

可写的内容: writerIndex--(capacity-1), 都是包含 

丢弃的内容(Discardable bytes)-->处理已经读过的内容, 通过调用discardReadBytes() 方法丢弃, 其实执行了一个System.arrayCopy的操作. 
BEFORE discardReadBytes() 

      +-------------------+------------------+------------------+ 
      | discardable bytes |  readable bytes  |  writable bytes  | 
      +-------------------+------------------+------------------+ 
      |                   |                  |                  | 
      0      <=      readerIndex   <=   writerIndex    <=    capacity 


  AFTER discardReadBytes() 

      +------------------+--------------------------------------+ 
      |  readable bytes  |    writable bytes (got more space)   | 
      +------------------+--------------------------------------+ 
      |                  |                                      | 
readerIndex (0) <= writerIndex (decreased)        <=        capacity 

netty中的字节拷贝,底层刚刚读取到的-->ChannelBuffer是零字节拷贝的; 
但是ChannelBuffer-->解码器的数据处理,这个一般来说是有字节拷贝的。 


4. 读取数据 
(1)Bytebuffer读取到并转换为ChannelBuffer,之后触发fireMessageReceived 
(2)用一个累积的ChannelBuffer读取,这个buffer是公用的, 每次读取前, 若这个Buffer已经读取了数据(一般是进行了累积),则先discardReadBytes()丢掉 
已经处理过得的数据;否则第一次读取直接传递原始的ChannelBuffer,这样若第一次就可以处理完,则避免了字节的复制,更高效,否则就将数据放到缓冲区里。 
(3)注意ChannelBuffer是动态分配大小的,一个channel有一个,那么要注意这个的大小,避免过大的问题。 

5. 写数据, 
(1)先将数据放到一个写的队列中 
(2)进行输出。 

6. 多线程处理事件 
(1)使用ExecutionHandler,只是加入了多线程机制,进行异步处理,之后仍然是调用之后的处理器进行处理。 
(2)事件的调度策略完全在于Executors的实现。 
(3)MemoryAwareThreadPoolExecutor只是简单的提交任务,变成异步处理而已,增加内存的控制 
(4)OrderedMemoryAwareThreadPoolExecutor保证来自同一个channel的事件A一定执行完后才执行事件B(即保证一个channel的执行顺序),但是同一个channel的所有事件 
是否应该固定在同一个线程中执行,这个则没有必要。 
实现的关键:ConcurrentMap, 就是一个channel,对应一个执行器,这个执行器在真正工作线程中被调度执行。 
(4.1)执行器里有一个队列,保证来自同一个channel的事件都添加到里面; 
(4.2)执行器执行时,依次取出事件任务进行执行。 

7. 客户端的处理 
(1)Boss线程,单独的负责连接的请求 
(1.1)创建NioClientSocketChannel对象;先创建SocketChannel(并且调用open方法),并预先分配一个worker--》 fireChannelOpen(this);--》执行bind方法 
socket().bind(localAddress),fireChannelBound(channel, channel.getLocalAddress());--》 ch.connect(remoteAddress)连接远程地址; 
(1.2)具体的处理都在NioClientSocketPipelineSink类里,针对连接进行一下说明,若见建立成功,则直接扔给worker线程处理;若建立失败,则扔给boss线程处理(因为是非阻塞的, 
可能一开始会建立不成功)。 
(2)worker线程,负责处理建立成功的连接 

8. SSL 
(1)客户端, SSLHandler放在位置1, 触发握手开始的操作放到最后一个Handler的channelConnected中, 
客户端握手过程(handshake): 
1. beginHandshake, 执行代理任务(就是ssl会话过程中的一些计算); 
2. 输出数据到服务端wrapNonAppData(这时没应用数据); 
3. 检查握手状态;