Netty学习笔记二(聊天室功能的初步认识)

今天只是聊天室实现的初步讲解,并不会真正的实现聊天室功能,具体的聊天室功能将会在下一个文章出现

3.Netty 客户端与服务端之间消息的传递 Hello World

3.1 服务端具体的代码实现

我一般来说会将代码的意思放在注释里面,可以将代码克隆下来 然后看注释即可

package com.demo.netty.secondexample;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.util.UUID;

/**
 * @author 自定义头信息  处理器
 */
public class MyServerHandler extends SimpleChannelInboundHandler<String> {
    /**
     *
     * @param ctx 上下文  核心
     * @param msg 请求对象  客户端发送过来的
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Thread.sleep(2000);
        //获取客户端地址  打印 客户端发送的请求带上地址
        System.out.println(ctx.channel().remoteAddress() + ", " + msg);
        //将客户端发送的消息加上UUID重新发给客户端
        ctx.channel().writeAndFlush("你的请求我收到了"+ UUID.randomUUID().toString()+"消息为:"+msg);
    }

    /**
     * 出现异常会调用这个
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

初始化器代码编写

package com.demo.netty.secondexample;

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;

/**
 * 客户端和服务端发送消息 添加消息处理消息头
 * @author huangfu
 */
public class MyServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        /**
         * 他是基于长度场的帧解码器 以后会做名词讲解
         * maxFrameLength:单个包最大的长度,这个值根据实际场景而定。
         * lengthFieldOffset:表示数据长度字段开始的偏移量
         * lengthFieldLength:数据长度字段的所占的字节数
         * lengthAdjustment:lengthAdjustment + 数据长度取值 = 数据长度字段之后剩下包的字节数
         * initialBytesToStrip:表示从整个包第一个字节开始,向后忽略的字节数
         */
        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());
    }
}

服务端启动类

package com.demo.netty.secondexample;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;

/**
 * 自定义服务端
 * @author huangfu
 */
public class MyServer {
    public static void main(String[] args) {
       //构造接收请求线程组和处理请求线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try{
            //创建启动入口
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    //处理被委托线程组
                    .childHandler(new MyServerInitializer());

            //绑定端口
            ChannelFuture sync = bootstrap.bind(8989).sync();
            //关闭资源
            sync.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

3.2客户端代码编写

客户端 自定义处理器实现

package com.demo.netty.secondexample.client;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.time.LocalDateTime;
import java.util.UUID;

/**
 * @author 自定义头信息  处理器
 */
public class MyClientHandler extends SimpleChannelInboundHandler<String> {
    /**
     *
     * @param ctx 上下文  核心
     * @param msg 请求对象  客户端发送过来的
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Thread.sleep(2000);
        //获取客户端地址
        System.out.println(ctx.channel().remoteAddress() + ", " + msg);
        //向服务端发送信息
        ctx.writeAndFlush("向你发送:"+ 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();
    }
}

客户端初始化器实现

package com.demo.netty.secondexample.client;

import com.demo.netty.secondexample.MyServerHandler;
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;

/**
 * 客户端和服务端发送消息
 * @author huangfu
 */
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());
    }
}

客户端 启动类实现

package com.demo.netty.secondexample.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * 自定义客户端
 * @author huangfu
 */
public class MyClient {
    public static void main(String[] args) {
        EventLoopGroup loopGroup = new NioEventLoopGroup();
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(loopGroup)
                    .channel(NioSocketChannel.class)
                    //客户端使用handler 他是针对一个Group
                    .handler(new MyClientInitializer());
            //绑定客户端端口
            ChannelFuture sync = bootstrap.connect("127.0.0.1",8989).sync();
            sync.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            loopGroup.shutdownGracefully();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值