栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

<2021SC@SDUSC>netty初步使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

<2021SC@SDUSC>netty初步使用

2021SC@SDUSC

文章目录
  • 一、前言
  • 二、服务端代码
  • 三、客户端代码
  • 四、总结

一、前言

在学习的第一个礼拜,先完成第二个目标,即使用netty编写服务端和客户端的程序,实现服务端和客户端的双向通信。当然,会在之后的学习过程中逐步完善。

二、服务端代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class Server {

    private final int PORT;

    public Server(int port) {
        this.PORT = port;
    }

    public void run() {
        //创建两个线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);
        try {
            //netty的引导程序
            ServerBootstrap bootstrap = new ServerBootstrap();
            //设置parentGroup和childGroup
            bootstrap.group(bossGroup, workerGroup)
                    //指定Channel类型
                    .channel(NioServerSocketChannel.class)
                    //设置队列中最大连接数
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //监控连接是否有效
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //客户端连接成功后,添加handler,注意ChannelInitilizer在注册成功后,会将自己删除
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                            //添加编解码器
                            pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                            pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            //自定义handler
                            pipeline.addLast(new SimpleChannelInboundHandler() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                    System.out.println(ctx.channel().remoteAddress() + ": " +msg);
                                    //将读取到的消息回写给客户端
                                    ctx.writeAndFlush("服务器收到消息: " + msg);
                                }

                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    System.out.println("连接已建立,来自" + ctx.channel().remoteAddress());
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    System.out.println("出现异常: " + cause.getMessage());
                                    //出现异常,关闭连接
                                    ctx.channel().close();
                                }
                            });
                        }
                    });
            //为服务器绑定端口,同步等待
            ChannelFuture future = bootstrap.bind(PORT).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new Server(8080).run();
    }

}

三、客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Client {

    private static final int PORT = 8080;
    private static final String HOST = "127.0.0.1";

    public Client() {}

    public void run() {
        //创建线程池,注意,与服务端不同,客户端只需要一个线程池 
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup)
                    //指定Channel类型
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                            pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                            pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new SimpleChannelInboundHandler() {
                                //将服务器发送的消息打印
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                    System.out.println(msg);
                                }

                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                    //IO事件,创建其它线程来处理
                                    ExecutorService executor = Executors.newSingleThreadExecutor();
                                    executor.submit(() -> {
                                        Scanner scanner = new Scanner(System.in);
                                        while (scanner.hasNextLine()) {
                                            String message = scanner.nextLine();
                                            ctx.writeAndFlush(message);
                                        }
                                    });
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    System.out.println(cause.getMessage());
                                    ctx.channel().closeFuture().sync();
                                }
                            });
                        }
                    });
            ChannelFuture future = bootstrap.connect(HOST, PORT).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new Client().run();
    }

}

四、总结

使用netty框架完成服务端对客户端发送消息的读取并且回写,初步完成了服务端与客户端的通信,之后预计将代码改为多个客户端的群聊系统。
此外,代码中存在的一个问题是客户端的退出问题,目前是强制关闭,之后会成其他方式。
之后的几篇博客,会就服务端的代码,分析netty启动流程的细节。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/287752.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号