Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
Netty简化socket编程,并没有使写出来的Socket效率变低,我写了一个所有都使用默认配置的服务端,模拟最常用的RPC方案,传输协议使用4字节长度加json串的方式来传输,测试服务端的通讯效率,测试结果如下。
从测试结果看,Netty性能是非常高的,在所有使用默认配置的情况下,单台服务器能够达到4万次请求解析,作为RPC框架是足够用的。还有一个有趣的现象是每次都创建连接和重用连接的差别不大,性能损耗对应用层几乎没影响,但是大家如果在应用环境中使用每次新建的情况,一定要进行压测,确认没影响后再使用。
public class AppNettyServer { public static void main(String[] args) throws Exception { System.out.print("Hello Netty\r\n"); int port = 9090; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { System.out.print("Invalid Port, Start Default Port: 9090"); } } try { NettyCommandServer commandServer = new NettyCommandServer(); System.out.print("Start listen socket, port " + port + "\r\n"); commandServer.bind(port); } catch (Exception e) { System.out.print(e.getMessage()); } } }
public class NettyCommandServer { public static InternalLogger logger = InternalLoggerFactory.getInstance(NettyCommandServer.class); public void bind(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024); serverBootstrap.handler(new LoggingHandler()); serverBootstrap.childHandler(new NettyChannelHandler()); ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); channelFuture.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } private class NettyChannelHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN, 64 * 1024, 0, 4, 0, 4, true)); socketChannel.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8"))); socketChannel.pipeline().addLast(new NettyCommandHandler()); } } }
public class NettyCommandHandler extends ChannelHandlerAdapter { private int counter = 0; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { try { String body = (String) msg; JsonDataObject request = JsonUtil.fromJson(body, JsonDataObject.class); counter = counter + 1; JsonDataObject response = new JsonDataObject(); response.setCode(0); response.setMsg("Success"); response.setData(counter+""); String respJson = JsonUtil.toJson(response); byte[] respUtf8 = respJson.getBytes("UTF-8"); int respLength = respUtf8.length; ByteBuf respLengthBuf = PooledByteBufAllocator.DEFAULT.buffer(4); respLengthBuf.writeInt(respLength); respLengthBuf.order(ByteOrder.BIG_ENDIAN); ctx.write(respLengthBuf); ByteBuf resp = PooledByteBufAllocator.DEFAULT.buffer(respUtf8.length); resp.writeBytes(respUtf8); ctx.write(resp); } catch (Exception e) { NettyCommandServer.logger.error(e.getMessage() + "\r\n"); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); sw.flush(); NettyCommandServer.logger.error(sw.toString()); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.close(); } }C#客户端代码
public class SocketClient : Object { private TcpClient tcpClient; public SocketClient() { tcpClient = new TcpClient(); tcpClient.Client.Blocking = true; } public void Connect(string host, int port) { tcpClient.Connect(host, port); } public void Disconnect() { tcpClient.Close(); } public string SendJson(string json) { byte[] bufferUTF8 = Encoding.UTF8.GetBytes(json); int jsonLength = System.Net.IPAddress.HostToNetworkOrder(bufferUTF8.Length); //转换为网络字节顺序,大头结构 byte[] bufferLength = BitConverter.GetBytes(jsonLength); tcpClient.Client.Send(bufferLength, 0, bufferLength.Length, SocketFlags.None); //发送4字节长度 tcpClient.Client.Send(bufferUTF8, 0, bufferUTF8.Length, SocketFlags.None); //发送Json串内容 byte[] bufferRecvLength = new byte[sizeof(int)]; tcpClient.Client.Receive(bufferRecvLength, sizeof(int), SocketFlags.None); //获取长度 int recvLength = BitConverter.ToInt32(bufferRecvLength, 0); recvLength = System.Net.IPAddress.NetworkToHostOrder(recvLength); //转为本地字节顺序 byte[] bufferRecvUtf8 = new byte[recvLength]; tcpClient.Client.Receive(bufferRecvUtf8, recvLength, SocketFlags.None); string recvCommand = Encoding.UTF8.GetString(bufferRecvUtf8, 0, recvLength); return recvCommand; } }