netty学习(6)---NIO服务器端实现
来源:互联网 发布:unity3d云雾特效 编辑:程序博客网 时间:2024/06/16 06:08
NIO服务器创建的步骤:
步骤一:打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道:
serverSocketChannel = ServerSocketChannel.open()
步骤二:绑定监听端口,设置连接为非阻塞模式:
serverSocketChannel.configureBlocking(false);//设置连接为非阻塞模式 serverSocketChannel.socket().bind(new InetSocketAddress(port), 1024)
步骤三:创建Reactor线程,创建多路复用器并启动线程:
selector = Selector.open(); //创建多路复用器Selectornew Thread(new ReactorTask()).start();
步骤四:将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件:
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
步骤五:多路复用器在线程run方法的无限循环体内轮询准备就绪的Key
步骤六:多路复用器接收到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路:
SocketChannel sc = ssc.accept(); //处理新的请求,完成TCP三次握手,建立物理链路
步骤七:设置客户端链路为非阻塞模式
sc.configureBlocking(false); //设置客户端链路为非阻塞模式
步骤八:将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,用来读取客户端发送的网络消息:
//add the new connection to the selector sc.register(selector, SelectionKey.OP_READ); //将客户端连接注册到多路复用器上,监听读操作,用来监听客户端发送的网络消息步骤九:异步读取客户端的请求消息到缓冲区:
int readBytes = sc.read(readBuffer);
步骤十:对ByteBuffer消息进行编码,如果有半包消息指针reset,继续读取后续的保温,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑编排.
步骤十一:将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端:
channel.write(writeBuffer);
下面用NIO实现TimeServer:
TimeServer
package com.panther.dong.netty.nio;/** * Created by panther on 15-8-26. */public class TimeServer { public static void main(String[] args) { int port = 12306; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (Exception e) { } } MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port); new Thread(timeServer, "NIO-MultiplexerTimeServer-001").start(); }}
MultiplexerTimeServer:
package com.panther.dong.netty.nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Date;import java.util.Iterator;import java.util.Set;/** * Created by panther on 15-8-26. */public class MultiplexerTimeServer implements Runnable { private Selector selector; private ServerSocketChannel serverSocketChannel; private volatile boolean stop; /** * 初始化多路复用器、绑定监听端口 * * @param port */ public MultiplexerTimeServer(int port) { try { selector = Selector.open(); //创建多路复用器Selector serverSocketChannel = ServerSocketChannel.open(); //打开ServerSocketChannel,用于监听客户端的连接 serverSocketChannel.configureBlocking(false);//设置连接为非阻塞模式 serverSocketChannel.socket().bind(new InetSocketAddress(port), 1024);//绑定监听端口,设置连接为非阻塞模式 serverSocketChannel .register(selector, SelectionKey.OP_ACCEPT); //将serversocketchannel注册到多路复用器Selector上,监听ACCEPT事件 System.out.println("The time server is start in port : " + port); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } public void stop() { this.stop = true; } @Override public void run() { //多路复用器无限轮询准备就绪的key while (!stop) { try { selector.select(1000); Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); SelectionKey key = null; while (iterator.hasNext()) { key = iterator.next(); handleInput(key); //多路复用器处理ACCEPT事件 iterator.remove(); } } catch (IOException e) { e.printStackTrace(); } } } private void handleInput(SelectionKey key) throws IOException { if (key.isValid()) { //处理新接入的请求消息 if (key.isAcceptable()) { //Accept the new Connection ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); //处理新的请求,完成TCP三次握手,建立物理链路 sc.configureBlocking(false); //设置客户端链路为非阻塞模式 //add the new connection to the selector sc.register(selector, SelectionKey.OP_READ); //将客户端连接注册到多路复用器上,监听读操作,用来监听客户端发送的网络消息 } if (key.isReadable()) { //read the data SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int readBytes = sc.read(readBuffer); if (readBytes > 0) { readBuffer.flip(); byte[] bytes = new byte[readBuffer.remaining()]; readBuffer.get(bytes); String body = new String(bytes, "UTF-8"); System.out.println("the time server receive order : " + body); String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER"; doWrite(sc, currentTime); } else if (readBytes < 0) { key.cancel(); sc.close(); } else { ; //读到0字节,忽略 } } } } private void doWrite(SocketChannel channel, String response) throws IOException { if (response != null && response.trim().length() > 0) { byte[] bytes = response.getBytes(); ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); writeBuffer.put(bytes); writeBuffer.flip(); channel.write(writeBuffer); } }}
0 0
- netty学习(6)---NIO服务器端实现
- Netty权威指南-NIO实现TimeServer服务器端源代码
- Netty学习 netty nio编程
- netty学习(5)--NIO基础知识
- Netty学习系列(二)-- NIO介绍
- NIO-netty-入门学习
- Netty学习-01-Nio
- (socket-nio-netty学习-1)socket,NIO,AIO基本概念
- nio实战之netty实现
- Netty学习3-NIO详解
- java NIO Netty实现原理浅析(转)
- java NIO Netty实现原理浅析(转)
- java NIO Netty实现原理浅析(转)
- nio学习之netty入门(1)---发送字符串
- nio学习之netty入门(3)---发送对象
- Netty学习之NIO---通道Channel(一)
- Netty学习之旅------线程模型前置篇Reactor反应堆设计模式实现(基于java.nio)
- 一起学Netty(十七)netty源码学习之大话java NIO
- iOS9中Bitcode的介绍及配置
- 希尔伯特空间
- 及时刷新子窗体
- Spring 表达式语言 (Spring Expression Language) SpEL
- eclipse中svn项目文件显示修改人修改日期设置
- netty学习(6)---NIO服务器端实现
- test5.2
- Tarjan算法
- Prolog第二天作业
- virtual IsEmpty() const=0中的const有什么用?
- 【总结】shader中存取光源的变量
- 美团2015 研发笔试 (1)
- sql 数据类型和 .net/C#的类型对应关系
- 值得学习的C语言开源项目