上节我们编写了netty服务端的程序,这节我们来写客户端程序
第一步:改造服务端程序为:
(1)MyServer类:
package com.ssy.netty.demo01; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * netty作为长连接的服务器基于websoket,实现客户端与服务器端长连接。 */ public class MyServer { public static void main(String[] args) { //负责接收客户端连接 EventLoopGroup bossGroup = new NioEventLoopGroup(); //处理连接 EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup,workerGroup) // 绑定线程池 .channel(NioServerSocketChannel.class) .childHandler(new MyServerInitializer()); //绑定端口号 ChannelFuture channelFuture = serverBootstrap.bind(8888).sync(); channelFuture.channel().closeFuture().sync(); } catch (Exception e) { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
(2)MyServerInitializer类
package com.ssy.netty.demo01; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; /** * 绑定客户端连接时候触发操作 */ public class MyServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //负载http 请求编码解码 //pipeline.addLast("httpServerCodec",new HttpServerCodec()); //实际处理请求 //pipeline.addLast("httpServerHandler",new HttpServerHandler()); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4)); pipeline.addLast(new LengthFieldPrepender(4)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new MyServerHandler()); } }
(3)MyServerHandler类
package com.ssy.netty.demo01; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import java.time.LocalDateTime; public class MyServerHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println(ctx.channel().remoteAddress()); System.out.println("client output:"+msg); ctx.writeAndFlush("from server:" + LocalDateTime.now()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
编写客户端主程序MyClient
package com.ssy.netty.demo01; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; public class MyClient { public static void main(String[] args) { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) // 绑定线程池 .channel(NioSocketChannel.class) .handler(new MyClientInitializer()); //绑定端口号 ChannelFuture channelFuture = bootstrap.connect("localhost",8888).sync(); channelFuture.channel().closeFuture().sync(); } catch (Exception e) { eventLoopGroup.shutdownGracefully(); } } }
第二步:编写MyClientInitializer
package com.ssy.netty.demo01; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; public class MyClientInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4)); pipeline.addLast(new LengthFieldPrepender(4)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new MyClientHandler()); } }
第三步:编写MyClientHandler
package com.ssy.netty.demo01; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import java.time.LocalDateTime; public class MyClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println(ctx.channel().remoteAddress()); System.out.println("client output:"+msg); ctx.writeAndFlush("from client:" + LocalDateTime.now()); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush("来自客户端的问候"); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
分别启动MyServer程序和MyClient程序,客户端成功调用服务端。
到此为止,我们已经完成了简单的netty服务端与客户端的通信程序,下节我们会对谷歌的Google Protobuf做一次详解,敬请期待吧!