Netty的一些笔记
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<Object, Executor>, 就是一个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. 检查握手状态; |
|