Netty 简单使用
本文分别使用了 bio、nio 和netty简单实现了一个SAY HELLO 的程序。通过代码的演进也可以看到从 bio、nio、到netty 的演进路线,更加清晰地认识到netty是如何利用nio来实现的。
BIO
HelloServer
启动一个server服务器,绑定到固定的端口
public static void main(String[] args) {
int port = 8080;
if (args == null && args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
try (ServerSocket serverSocket = new ServerSocket(port)) {
Socket socket = null;
while (true) {
socket = serverSocket.accept();
new Thread(new TimeserverHandler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
HelloServerHandler
服务端处理请求的程序
private static Logger logger = LoggerFactory.getLogger(TimeserverHandler.class);
private Socket socket;
public TimeserverHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
) {
String hello = null;
String body = null;
while (true) {
body = in.readLine();
if (body == null) {
break;
}
logger.info("The time server receive order :{}", body);
hello = "SAY HELLO BABY".equalsIgnoreCase(body) ? "HELLO" : "BAD ORDER";
out.println(hello);
}
} catch (Exception e) {
}
}
HelloClient
客户端
public static void main(String[] args) {
int port = 8080;
if (args == null && args.length > 0) {
try{
port = Integer.parseInt(args[0]);
}catch (NumberFormatException e){
e.printStackTrace();
}
}
try(Socket socket = new Socket("127.0.0.1",port);
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
){
out.println("SAY HELLO BABY");
System.out.println("Send order 2 server succeed.");
String resp = in.readLine();
System.out.println("Now is : " + resp);
}catch (Exception e){
e.printStackTrace();
}
}
NIO
HelloServer
public static void main(String[] args) {
int port = 8080;
if (args == null && args.length > 0) {
port = Integer.parseInt(args[0]);
}
MultiplexerHelllloServer server = new MultiplexerHelllloServer(port);
new Thread(server,"NIO-MultiplexerHelloServer-001").start();
}
MultiplexerHelllloServer
server端处理请求的逻辑
private Selector selector;
private ServerSocketChannel server;
private volatile boolean stop = false;
/**
* 初始化多路复用监听器、绑定监听端口
*
* @param port
*/
public MultiplexerHelloServer(int port) {
try {
//打开选择器
selector = Selector.open();
//创建一个serverSocketChannel
server = ServerSocketChannel.open();
server.configureBlocking(false);
//绑定地址
server.bind(new InetSocketAddress(port), 1024);
//注册到一个多路复用选择器上 监听事件 ACCEPT
server.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("The hello server is start in port : " + port);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public void stop() {
this.stop = true;
}
@Override
public void run() {
while (!stop) {
try {
selector.select(1000);
//获取到所有就绪的selectionKey
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
try {
handlerInput(key);
} catch (IOException e) {
key.cancel();
if (key.channel() != null) {
key.channel().close();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (selector != null) {
try {
selector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 具体的处理步骤
* 根据不同的事件的种类,来去做不同的处理
* @param key
* @throws IOException
*/
private void handlerInput(SelectionKey key) throws IOException {
if (key.isValid()) {
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int read = sc.read(readBuffer);
if (read > 0) {
readBuffer.flip();
byte[] bytes = new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String body = new String(bytes);
System.out.println("The hello server receive order : "
+ body);
String currentTime = "SAY HELLO BABY"
.equalsIgnoreCase(body) ? "HELLO"
: "BAD ORDER";
doWrite(sc, currentTime);
//返回值为-1:链路已经关闭,需要关闭SocketChannel,释放资源。
} else if (read < 0) {
key.channel();
sc.close();
}
}
}
}
/**
* 应答客户端
* @param channel
* @param response
* @throws IOException
*/
private void doWrite(SocketChannel channel, String response) throws IOException {
if (response != null && response.length() > 0) {
byte[] bytes = response.getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
writeBuffer.put(bytes);
writeBuffer.flip();
channel.write(writeBuffer);
}
}
HelloClient
public static void main(String[] args) {
int port = 8080;
if (args != null && args.length > 0) {
port = Integer.parseInt(args[0]);
}
new Thread(new TimeClientHandler("127.0.0.1",port),"HelloClient-001").start();
}
HelloClientHandler