1.简介
Netty是由JBOSS提供的一个Java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。官网:http://netty.io/
MessagePack(编码后字节流特小,编解码速度超快,同时几乎支持所有主流编程语言,详情见官网:http://msgpack.org/)(待进一步学习)
曾经用过.net开源框架supersocket,应用于物联网网关开发,但是考虑到跨平台问题,更倾向于采用JAVA语言来实现。(待进一步学习)
2.实现步骤
(1)采用Eclipse开发工具,新建maven项目
(2)maven引用:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>NettyTest</groupId>
<artifactId>NettyTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>NettyTest</name>
<description>NettyTest</description>
<modules>
<module>NettyServer</module>
<module>NettyClient</module>
</modules>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.9.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.msgpack/msgpack 是一个高效的二进制序列化格式。它让你像JSON一样可以在各种语言之间交换数据。但是它比JSON更快、更小。以后再研究 -->
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack</artifactId>
<version>0.6.12</version>
</dependency>
</dependencies>
</project>
(3)MyServerHandler.java:
package com.jiantsing.test;
import java.util.Date;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class MyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("server channelRead..");
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "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";
String currentTime = new Date(System.currentTimeMillis()).toString();
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("server channelReadComplete..");
ctx.flush();//刷新后才将数据发出到SocketChannel
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
System.out.println("server exceptionCaught..");
ctx.close();
}
}
(4)MyServer.java:
package com.jiantsing.test;
import java.util.logging.Logger;
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 MyServer {
private static final Logger logger = Logger
.getLogger(MyServer.class.getName());
public void bind(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 配置服务器的NIO线程租
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChildChannelHandler());
// 绑定端口,同步等待成功
ChannelFuture f = b.bind(port).sync();
logger.info("服务器启动成功!");
// 等待服务端监听端口关闭
f.channel().closeFuture().sync();
} finally {
// 优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel arg0) throws Exception {
System.out.println("server initChannel..");
arg0.pipeline().addLast(new MyServerHandler());
}
}
public static void main(String[] args) throws Exception {
int port = 9000;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
new MyServer().bind(port);
}
}
(5)MyClientHandler.java:
package com.jiantsing.test;
import java.util.logging.Logger;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class MyClientHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = Logger
.getLogger(MyClientHandler.class.getName());
private ChannelHandlerContext ctx;
private final ByteBuf firstMessage;
public MyClientHandler() {
byte[] req = "QUERY TIME ORDER".getBytes();
firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//与服务端建立连接后
System.out.println("client channelActive..");
this.ctx = ctx;
ctx.writeAndFlush(firstMessage);
}
public boolean sendMessage(String msg)
{
boolean result;
try{
ByteBuf msgByte;
byte[] req = msg.getBytes();
msgByte = Unpooled.buffer(req.length);
msgByte.writeBytes(req);
ctx.writeAndFlush(msgByte);
result=true;
}catch (Exception e) {
// TODO: handle exception
result=false;
logger.warning(e.getMessage());
}
return result;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("client channelRead..");
//服务端返回消息后
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("Now is :" + body);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
System.out.println("client exceptionCaught..");
// 释放资源
logger.warning("Unexpected exception from downstream:"
+ cause.getMessage());
ctx.close();
}
}
(6)MyClient.java:
package com.jiantsing.test;
import java.util.logging.Logger;
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;
public class MyClient {
private static final Logger logger = Logger
.getLogger(MyClient.class.getName());
private MyClientHandler clientHandler = new MyClientHandler();
public void connect(int port, String host) throws Exception {
// 配置客户端NIO线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel arg0)
throws Exception {
System.out.println("client initChannel..");
arg0.pipeline().addLast(clientHandler);
}
});
// 发起异步连接操作
ChannelFuture f = b.connect(host, port).sync();
logger.info("客户端已经连接..");
clientHandler.sendMessage("发送数据测试1");
clientHandler.sendMessage("发送数据测试2");
clientHandler.sendMessage("发送数据测试3");
// 等待客户端链路关闭
f.channel().closeFuture().sync();
} finally {
// 优雅退出,释放NIO线程组
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 9000;
if (args != null && args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
}
}
new MyClient().connect(port, "127.0.0.1");
}
}
(7)运行结果:
-------------------------------------------------------------------------------------
四月 15, 2017 12:59:14 下午 com.jiantsing.test.MyServer bind
信息: 服务器启动成功!
server initChannel..
server channelRead..
The time server receive order:QUERY TIME ORDER
server channelReadComplete..
server channelRead..
The time server receive order:发送数据测试1
server channelReadComplete..
server channelRead..
The time server receive order:发送数据测试2
server channelReadComplete..
server channelRead..
The time server receive order:发送数据测试3
server channelReadComplete..
server channelReadComplete..
server exceptionCaught..
-----------------------------------------------------------------------------------------------
client initChannel..
client channelActive..
四月 15, 2017 12:59:25 下午 com.jiantsing.test.MyClient connect
信息: 客户端已经连接..
client channelRead..
Now is :Sat Apr 15 12:59:25 CST 2017
client channelRead..
Now is :Sat Apr 15 12:59:25 CST 2017
client channelRead..
Now is :Sat Apr 15 12:59:25 CST 2017
client channelRead..
Now is :Sat Apr 15 12:59:25 CST 2017
--------------------------------------------------------------------------------------------------