netty 聊天入门程序

pom引入

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.48.Final</version>
</dependency>

创建四个文件

server、serverHandler 

client、clientHandler

package com.kaige.admin.netty1;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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 lombok.extern.slf4j.Slf4j;

import java.net.SocketAddress;
import java.util.Scanner;

/**
 * <p>
 * client
 *
 * @author wdz
 * @since 2021-06-01
 */
@Slf4j
public class ChatClient {

    public void run() {
        // 创建线程组
        NioEventLoopGroup group = new NioEventLoopGroup();
        // 创建启动助手
        Bootstrap b = new Bootstrap();
        // 设置线程组
        b.group(group);
        // 设置客户端通道实现
        b.channel(NioSocketChannel.class);
        // 创建通道初始化对象
        b.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel channel) throws Exception {
                // 自定义handler 配置加载
                ChannelPipeline pipeline = channel.pipeline();
                // 编解码器要与handler中继承的父类泛型保持一致:SimpleChannelInboundHandler
                // 添加解码器
                pipeline.addLast("decoder",new StringDecoder());
                // 添加编码器
                pipeline.addLast("encoder",new StringEncoder());
                // 自定义handler
                channel.pipeline().addLast(new ChatClientHandler());
            }
        });
        log.info("---------客户端已就绪-----------");
        ChannelFuture localhost = null;
        try {
            localhost = b.connect("localhost", 8888).sync();
            Channel channel = localhost.channel();
            SocketAddress socketAddress = channel.localAddress();
            log.info("---------IP:{}",socketAddress.toString());
            Scanner sc = new Scanner(System.in);
            while (sc.hasNextLine()){
                String s = sc.nextLine();
                channel.writeAndFlush(s);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭链接
            if (localhost != null) {
                try {
                    localhost.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            group.shutdownGracefully();
            log.info("------客户端-----关闭-------------");
        }
    }

    public static void main(String[] args) {
        new ChatClient().run();
    }
}
package com.kaige.admin.netty1;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * client h
 *继承类发生变化,便于将编解码使用
 * @author wdz
 * @since 2021-06-01
 */
@Slf4j
public class ChatClientHandler extends SimpleChannelInboundHandler<String> {


    /**
     * 读取服务端广播信息
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        log.info("----接收到服务器信息--:{}",msg);
    }





}
package com.kaige.admin.netty1;

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 lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * server
 *
 * @author wdz
 * @since 2021-06-01
 */
@Slf4j
public class ChatServer {

    private int port;

    public ChatServer(int port) {
        this.port = port;
    }

    public void run() {
        // 创建线程组,接收客户端链接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 处理网络操作:IO
        EventLoopGroup workGroup = new NioEventLoopGroup();
        // 创建服务器端启动助手,配置服务端信息
        ServerBootstrap sb = new ServerBootstrap();
        // 设置线程组
        sb.group(bossGroup, workGroup);
        // 使用NioServerSocketChannel作为服务器端的通道实现
        sb.channel(NioServerSocketChannel.class);
        // 设置线程对列中等待链接数量
        sb.option(ChannelOption.SO_BACKLOG, 128);
        // 设置活动保持链接状态
        sb.childOption(ChannelOption.SO_KEEPALIVE, true);
        // 初始化通道
        sb.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel channel) throws Exception {
                // 自定义handler 配置加载
                ChannelPipeline pipeline = channel.pipeline();
                // 编解码器要与handler中继承的父类泛型保持一致:SimpleChannelInboundHandler
                // 添加解码器
                pipeline.addLast("decoder", new StringDecoder());
                // 添加编码器
                pipeline.addLast("encoder", new StringEncoder());
                // 自定义handler
                pipeline.addLast(new ChatServerHandler());
            }
        });
        log.info("---------服务器端已就绪--------");
        // 绑定端口,非阻塞
        ChannelFuture sync = null;
        try {
            // 异步绑定,sync同步阻塞
            sync = sb.bind(port).sync();
            log.info("---------服务启动成功--------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭通道、线程组
            if (sync != null) {
                try {
                    sync.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
            log.info("------服务端-----关闭-------------");
        }
    }

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

}

package com.kaige.admin.netty1;

import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * server h
 * 服务器端业务处理类,处理服务器接收到的数据
 * @author wdz
 * @since 2021-06-01
 *
 */
@Slf4j
public class  ChatServerHandler extends SimpleChannelInboundHandler<String> {

    public static List<Channel> channels = new ArrayList<>();


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // 将客户端通道存储
        channels.add(channel);
        log.info("----------客户端就绪----------:{}上线", channel.remoteAddress().toString());
    }
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channels.remove(channel);
        log.info("----------客户端未就绪----------:{}离线", channel.remoteAddress().toString());
    }

    /**
     * 重写读取数据方法
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        log.info("服务端读取到信息:{}",msg);
        Channel channel = ctx.channel();
        // 给非当前用户通道进行广播(发送信息)
        for (int i = 0; i < channels.size(); i++) {
            Channel channel1 = channels.get(i);
            if (channel1 != channel){
                channel1.writeAndFlush(channel.remoteAddress()+"发送消息:"+msg);
            }
        }
    }

    /**
     * 重写数据读取完毕方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        JSONObject object = new JSONObject();
        object.put("msg","服务器数据读取完成返回信息");
        object.put("code","200");
        log.info("--------读取消息完成返回信息:{}",object.toJSONString());
        ctx.writeAndFlush(Unpooled.copiedBuffer(object.toString(),CharsetUtil.UTF_8));
    }

    /**
     * 重写异常发生
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 发生异常,关闭通道
        log.info("----exceptionCaught----发生异常,关闭通道");
        ctx.close();
    }

}

先启动ChatServer 然后再启动ChatClient 

idea 启动多个main方法配置:

客户端启动成功(多个)后,即可在控制台中输入聊天信息,实现简单聊天

猜你喜欢

转载自blog.csdn.net/wdz985721191/article/details/117448476