java使用Netty实现点对点聊天

版权声明:如要转载,请注明出处 https://blog.csdn.net/qq_36480491/article/details/84711553

最近学习服务器开放,实现客户端(APP)与硬件设备之间的通信,我一想到socket,经过查询资料发现socket实现起来非常麻烦,同时也发现一个比较好的框架netty,觉得很不错,就开始尝试用他来撸一个点对点聊天系统,想了解的小伙伴可以自行去学习一下netty
一、一开始是导包,我是导入这三个包
在这里插入图片描述

二、开启服务器,话不多说直接上代码,比较代码很简单
DiscardServer.java 主函数开启服务

public class DiscardServer implements Runnable{

    private int port;

    private DiscardServer(int port) {
        this.port = port;
    }

    public void run()  {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // (3)
                    .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new DiscardServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)          // (5)
                    .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

            // Bind and start to accept incoming connections.
            Channel f = b.bind(port).sync().channel(); // (7)

            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) throws Exception {
        int port;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 1001;
        }

       new Thread( new DiscardServer(port)).start();
    }
}

DiscardServerHandler.java 负责通信和消息处理

public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)

        ByteBuf in = (ByteBuf) msg;
        System.out.print(in.toString(io.netty.util.CharsetUtil.US_ASCII));
        // 以静默方式丢弃接收的数据
      //  ((ByteBuf) msg).release(); // (3)
//        ctx.writeAndFlush(firstMSG);
     //   String name=in.toString(io.netty.util.CharsetUtil.US_ASCII);
        ApplicationContext.dealMessage(in.toString(io.netty.util.CharsetUtil.US_ASCII),ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ApplicationContext.writeMessage("ni hao a",ctx);
        System.out.println("this"+ctx.channel().remoteAddress().toString());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // 出现异常时关闭连接。
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        super.channelWritabilityChanged(ctx);
    }
}

ApplicationContext.java 负责客户端存储,消息协议制度和处理,定义Map来存储用户ID和客户端

public class ApplicationContext {
    private static Map<Integer, ChannelHandlerContext> onlineUsers = new HashMap<Integer, ChannelHandlerContext>();//存储用户客户端消息

    private static void add(Integer uid, ChannelHandlerContext ctx) {
        onlineUsers.put(uid, ctx);
    }

 

    public static void remove(Integer uid) {
        onlineUsers.remove(uid);
    }

    private static ChannelHandlerContext getContext(Integer uid) {
        return onlineUsers.get(uid);
    }

    /**
     * 消息处理、自定义协议
     * @param message 消息
     * @param ctx 客户端
     */
    static void dealMessage(String message, ChannelHandlerContext ctx) {
        String[] strings = message.split("#");
        System.out.println(strings.length+" length");
        //定义协议#号隔开数组下标0:数据类型、1:接收端用户ID、2:发送端ID、3内容
        if (strings.length != 4)
            return;
        switch (strings[0]) {
            case "0"://认证客户端
                add(Integer.valueOf(strings[2]), ctx);
                break;

            case "2"://指定用户发送
                ChannelHandlerContext ctxTwo = getContext(Integer.valueOf(strings[1]));
                if (ctxTwo != null)
                    writeMessage(message,ctxTwo);
                else
                    writeMessage("is get out\n",ctx);
                    break;
        }
    }

    /**
     * 发送消息
     * @param message 消息
     * @param ctx 客户端
     */
    static void writeMessage(String message, ChannelHandlerContext ctx) {
        ctx.writeAndFlush(Unpooled.buffer(message.getBytes().length).writeBytes(message.getBytes()));
    }
}

接下来就大功告成了

三、调试方式
连接服务器,收到服务器返回(ni hao a)的消息, 马上返回消息绑定客户端如0#1#2#3,及表示自己客户端的id为2,其他客户端可通过id来向自己发送消息,发送消息给其他客户端如2#1#2#4,给id为1的客户端发送消息4。
上面那个只是我简单设置的一个协议,大家使用可以的话可以设置其他的协议或者数据格式json、XML等等

猜你喜欢

转载自blog.csdn.net/qq_36480491/article/details/84711553