[关闭]
@adamhand 2018-12-31T05:10:05.000000Z 字数 3673 阅读 735

Netty系列(2)--第一个netty程序


简介

在了解了Netty基本概念和框架的基础上,参考《Netty实战》,编写了第一个程序--Echo客户端和服务器。

那么,什么是Echo呢?Echo就是经常说的回显程序,即服务器收到一个客户端的请求,就会对客户端进行响应。更简单的Echo例子是,客户端发送给服务器一个字符串,服务器将这个字符串原封不动地再发送给客户端。

下图显示了这个回显程序的一个架子。



实现

首先启动服务器,这时服务器就处在监听状态。当客户端连接成功后,客户端程序会调用channelActive方法,在这个方法中,将Netty rocks这个字符串写入缓冲区并刷出去。

服务端在接受到消息之后,会调用channelRead方法,将Netty rocks保存到一个缓冲区数组中,并打印Server received: Netty rocks,然后再将这个字符串返还给客户端。

客户端接受到服务反馈回来的字符串后,会打印Client received: Netty rocks消息。

客户端程序的实现

  1. //EchoClientHandler
  2. public class EchoClientHander extends SimpleChannelInboundHandler<ByteBuf> {
  3. //在连接建立的时候被调用,将信息写入缓冲区
  4. @Override
  5. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  6. ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks", CharsetUtil.UTF_8));
  7. }
  8. //每次接收数据是都会被调用
  9. @Override
  10. protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) {
  11. System.out.println("Client received: "+byteBuf.toString(CharsetUtil.UTF_8));
  12. }
  13. @Override
  14. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  15. cause.printStackTrace();
  16. ctx.close();
  17. }
  18. }
  1. //EchoClient
  2. public class EchoClient {
  3. private final String host;
  4. private final int port;
  5. EchoClient(String host, int port){
  6. this.port = port;
  7. this.host = host;
  8. }
  9. public void start() throws Exception {
  10. EventLoopGroup group = new NioEventLoopGroup();
  11. try {
  12. Bootstrap b = new Bootstrap();
  13. b.group(group)
  14. .channel(NioSocketChannel.class)
  15. .remoteAddress(new InetSocketAddress(host, port))
  16. .handler(new ChannelInitializer<SocketChannel>() {
  17. @Override
  18. protected void initChannel(SocketChannel socketChannel) {
  19. socketChannel.pipeline().addLast(new EchoClientHander());
  20. }
  21. });
  22. ChannelFuture f = b.connect().sync();
  23. f.channel().closeFuture().sync();
  24. } finally {
  25. group.shutdownGracefully().sync();
  26. }
  27. }
  28. public static void main(String[] args) throws Exception {
  29. String host;
  30. int port;
  31. if(args.length == 2){
  32. host = args[0];
  33. port = Integer.parseInt(args[1]);
  34. }else {
  35. host = "127.0.0.1";
  36. port = 8080;
  37. }
  38. new EchoClient(host, port).start();
  39. }
  40. }

服务器程序的实现

  1. public class EchoServerHandler extends ChannelInboundHandlerAdapter {
  2. //每个传入的消息都要调用这个方法
  3. @Override
  4. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  5. ByteBuf in = (ByteBuf)msg; //将接收到的消息存入ByteBuf中
  6. System.out.println("Server received: "+in.toString(CharsetUtil.UTF_8));
  7. ctx.write(in);
  8. }
  9. //通知ChannelInbountHandler消息已经读完
  10. @Override
  11. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  12. ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
  13. }
  14. //异常处理
  15. @Override
  16. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  17. cause.printStackTrace(); //打印异常日志
  18. ctx.close(); //关闭channel
  19. }
  20. }
  1. public class EchoServer {
  2. private final int port;
  3. public EchoServer(int port) {
  4. this.port = port;
  5. }
  6. public static void main(String[] args) throws Exception {
  7. int port;
  8. //如果调用函数的时候传进来端口值,就使用端口值,否则使用8080
  9. if(args.length > 0){
  10. port = Integer.parseInt(args[0]);
  11. }else{
  12. port = 8080;
  13. }
  14. new EchoServer(port).start();
  15. }
  16. public void start() throws Exception {
  17. final EchoServerHandler echoServerHandler = new EchoServerHandler();
  18. //NioEventLoopGroup 是用来处理I/O操作的多线程事件循环器,
  19. //Netty提供了许多不同的EventLoopGroup的实现用来处理不同传输协议。
  20. EventLoopGroup group = new NioEventLoopGroup();
  21. try {
  22. //ServerBootstrap 是一个启动NIO服务的辅助启动类 可以在这个服务中直接使用Channel
  23. ServerBootstrap b = new ServerBootstrap();
  24. //ServerSocketChannel以NIO的selector为基础进行实现的,用来接收新的连接
  25. //ChannelInitializer是一个特殊的处理类,他的目的是帮助使用者配置一个新的Channel。
  26. //并将新的channel实例添加到ChannelPipeline中
  27. b.group(group).
  28. channel(NioServerSocketChannel.class).
  29. localAddress(new InetSocketAddress(port)).
  30. childHandler(new ChannelInitializer<SocketChannel>() {
  31. @Override
  32. protected void initChannel(SocketChannel socketChannel) {
  33. socketChannel.pipeline().addLast(echoServerHandler);
  34. }
  35. });
  36. //绑定服务器,阻塞直到绑定完成。
  37. ChannelFuture f = b.bind().sync();
  38. f.channel().closeFuture().sync();
  39. } finally {
  40. group.shutdownGracefully().sync();
  41. }
  42. }
  43. }

程序运行结果

客户端结果:

  1. Client received: Netty rocks

服务器结果:

  1. Server received: Netty rocks

参考:

Netty实战


添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注