Java NIO框架Netty簡單使用的示例
之前寫了一篇文章:Java 網(wǎng)絡(luò)IO編程總結(jié)(BIO、NIO、AIO均含完整實(shí)例代碼),介紹了如何使用Java原生IO支持進(jìn)行網(wǎng)絡(luò)編程,本文介紹一種更為簡單的方式,即Java NIO框架。
Netty是業(yè)界最流行的NIO框架之一,具有良好的健壯性、功能、性能、可定制性和可擴(kuò)展性。同時(shí),它提供的十分簡單的API,大大簡化了我們的網(wǎng)絡(luò)編程。
同Java IO介紹的文章一樣,本文所展示的例子,實(shí)現(xiàn)了一個(gè)相同的功能。
1、服務(wù)端
Server:
package com.anxpp.io.calculator.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class Server {
private int port;
public Server(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture f = b.bind(port).sync();
System.out.println("服務(wù)器開啟:"+port);
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 9090;
}
new Server(port).run();
}
}
ServerHandler:
package com.anxpp.io.calculator.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.UnsupportedEncodingException;
import com.anxpp.io.utils.Calculator;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
ByteBuf in = (ByteBuf) msg;
byte[] req = new byte[in.readableBytes()];
in.readBytes(req);
String body = new String(req,"utf-8");
System.out.println("收到客戶端消息:"+body);
String calrResult = null;
try{
calrResult = Calculator.Instance.cal(body).toString();
}catch(Exception e){
calrResult = "錯(cuò)誤的表達(dá)式:" + e.getMessage();
}
ctx.write(Unpooled.copiedBuffer(calrResult.getBytes()));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
/**
* 異常處理
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
package com.anxpp.io.calculator.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.UnsupportedEncodingException;
import com.anxpp.io.utils.Calculator;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
ByteBuf in = (ByteBuf) msg;
byte[] req = new byte[in.readableBytes()];
in.readBytes(req);
String body = new String(req,"utf-8");
System.out.println("收到客戶端消息:"+body);
String calrResult = null;
try{
calrResult = Calculator.Instance.cal(body).toString();
}catch(Exception e){
calrResult = "錯(cuò)誤的表達(dá)式:" + e.getMessage();
}
ctx.write(Unpooled.copiedBuffer(calrResult.getBytes()));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
/**
* 異常處理
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
2、客戶端
Client:
package com.anxpp.io.calculator.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.Scanner;
public class Client implements Runnable{
static ClientHandler client = new ClientHandler();
public static void main(String[] args) throws Exception {
new Thread(new Client()).start();
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
while(client.sendMsg(scanner.nextLine()));
}
@Override
public void run() {
String host = "127.0.0.1";
int port = 9090;
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(client);
}
});
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
}
}
}
ClientHandler:
package com.anxpp.io.calculator.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.UnsupportedEncodingException;
public class ClientHandler extends ChannelInboundHandlerAdapter {
ChannelHandlerContext ctx;
/**
* tcp鏈路簡歷成功后調(diào)用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
}
public boolean sendMsg(String msg){
System.out.println("客戶端發(fā)送消息:"+msg);
byte[] req = msg.getBytes();
ByteBuf m = Unpooled.buffer(req.length);
m.writeBytes(req);
ctx.writeAndFlush(m);
return msg.equals("q")?false:true;
}
/**
* 收到服務(wù)器消息后調(diào)用
* @throws UnsupportedEncodingException
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req,"utf-8");
System.out.println("服務(wù)器消息:"+body);
}
/**
* 發(fā)生異常時(shí)調(diào)用
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
3、用于計(jì)算的工具類
package com.anxpp.io.utils;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public enum Calculator {
Instance;
private final static ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
public Object cal(String expression) throws ScriptException{
return jse.eval(expression);
}
}
4、測試
分別啟動(dòng)服務(wù)端和客戶端,然后再客戶端控制臺輸入表達(dá)式:
1+5+5+5+5+5 客戶端發(fā)送消息:1+5+5+5+5+5 服務(wù)器消息:26 156158*458918+125615 客戶端發(fā)送消息:156158*458918+125615 服務(wù)器消息:7.1663842659E10 1895612+555+5+5+5+5+5+5+5-5*4/4 客戶端發(fā)送消息:1895612+555+5+5+5+5+5+5+5-5*4/4 服務(wù)器消息:1896197
可以看到服務(wù)端返回的結(jié)果。
查看服務(wù)端控制臺:
服務(wù)器開啟:9090 收到客戶端消息:1+5+5+5+5+5 收到客戶端消息:156158*458918+125615 收到客戶端消息:1895612+555+5+5+5+5+5+5+5-5*4/4
5、更多
相關(guān)文章:
Java 網(wǎng)絡(luò)IO編程總結(jié)(BIO、NIO、AIO均含完整實(shí)例代碼)
本文例子以及Java BIO NIO AIO例子的源碼Git地址:https://github.com/anxpp/Java-IO.git
后續(xù)會繼續(xù)更新Netty相關(guān)內(nèi)容,直到一個(gè)簡陋的通訊服務(wù)器完成。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot定制化Starter實(shí)現(xiàn)方法
小伙伴們曾經(jīng)可能都經(jīng)歷過整天寫著CURD的業(yè)務(wù),都沒寫過一些組件相關(guān)的東西,這篇文章記錄一下SpringBoot如何自定義一個(gè)Starter。原理和理論就不用多說了,可以在網(wǎng)上找到很多關(guān)于該方面的資料,這里主要分享如何自定義2023-01-01
Java實(shí)現(xiàn)精準(zhǔn)Excel數(shù)據(jù)排序的方法詳解
在數(shù)據(jù)處理或者數(shù)據(jù)分析的場景中,需要對已有的數(shù)據(jù)進(jìn)行排序,在Excel中可以通過排序功能進(jìn)行整理數(shù)據(jù),而在Java中,則可以借助Excel表格插件對數(shù)據(jù)進(jìn)行批量排序,下面我們就來學(xué)習(xí)一下常見的數(shù)據(jù)排序方法吧2023-10-10
教你怎么在IDEA中創(chuàng)建java多模塊項(xiàng)目
這篇文章主要介紹了教你怎么在IDEA中創(chuàng)建java多模塊項(xiàng)目,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
SpringBoot如何配置文件properties和yml
這篇文章主要介紹了SpringBoot如何配置文件properties和yml問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Spring注解驅(qū)動(dòng)擴(kuò)展原理BeanFactoryPostProcessor
這篇文章主要介紹了Spring注解驅(qū)動(dòng)擴(kuò)展原理BeanFactoryPostProcessor,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
Java 替換字符串右側(cè)出現(xiàn)的第一個(gè)子串方式
這篇文章主要介紹了Java 替換字符串右側(cè)出現(xiàn)的第一個(gè)子串方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08

