ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

netty(五)Client与Server双向通信

2022-06-03 15:32:00  阅读:123  来源: 互联网

标签:netty 肥宅 双向通信 Client io import new 服务端


一、本章重点

ChannelInboundHandlerAdapter.java【管道连接处理适配器】

  作用:定义了channelActive()channelRead()等方法,用于定义netty管道操作过程中的一些处理方法。

ChannelInboundHandlerAdapter.channelActive()【管道连接成功后回调,操作方法】

  作用:连接上服务端后会被回调。

ChannelInboundHandlerAdapter.java【管道连接成功后回调,读取方法】

  作用:接收到客户端发来的数据之后会被回调。

二、客户端代码

NettyNIOClient【Netty实现的NIO客户端】

package client;

import handler.ClinetHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * Netty实现的NIO客户端【向服务端输出数据、读取数据】
 *
 * @author 有梦想的肥宅
 * @date 2022/5/1
 */
public class NettyNIOClient {
    public static void main(String[] args) throws InterruptedException {
        //1、创建客户端启动引导类,用于引导客户端的启动工作和连接服务端
        Bootstrap bootstrap = new Bootstrap();

        //2、创建NioEventLoopGroup对象,作用类似线程组
        NioEventLoopGroup group = new NioEventLoopGroup();

        //3、配置客户端启动引导类
        bootstrap
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        //PS:这里配置建立连接后的处理逻辑【自定义handler】
                        ch.pipeline().addLast(new ClinetHandler());
                    }
                });

        //4、与服务端建立连接
        bootstrap.connect("127.0.0.1", 8000).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("1、【有梦想的肥宅】Client连接Server成功!");
            } else {
                System.out.println("1、【有梦想的肥宅】Client连接Server失败!");
            }
        });

    }
}

ClinetHandler【客户端连接处理类】

package handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 客户端连接处理类
 *
 * @author 有梦想的肥宅
 * @date 2022/5/19
 */
public class ClinetHandler extends ChannelInboundHandlerAdapter {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /*PS:channelActive()方法在建立连接后会被回调*/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println("2、【有梦想的肥宅】Client开始写出数据:" + sdf.format(new Date()));

        //1、获取数据
        //1.1 获取二进制抽象ByteBuf对象
        ByteBuf byteBuf = ctx.alloc().buffer();
        //1.2 准备数据,并指定字符串的字符集为UTF-8
        byte[] bytes = "【有梦想的肥宅】Client发消息啦~".getBytes(StandardCharsets.UTF_8);
        //1.3 填充数据到ByteBuf对象
        byteBuf.writeBytes(bytes);

        //2、写数据
        Thread.sleep(1000);
        ctx.channel().writeAndFlush(byteBuf);
        System.out.println("3、【有梦想的肥宅】Client写出数据完毕:" + sdf.format(new Date()));
    }

    /*PS:channelRead()方法在接收到数据之后会被回调*/
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println("8、【有梦想的肥宅】Client开始接收数据:" + sdf.format(new Date()));

        //1、强转接收到的消息内容
        ByteBuf byteBuf = (ByteBuf) msg;

        //2、在服务端输出接收到的消息内容
        Thread.sleep(1000);
        System.out.println("9、【有梦想的肥宅】Client接收到Server回复的消息:" + byteBuf.toString(StandardCharsets.UTF_8) + sdf.format(new Date()));
    }

}

三、服务端代码

NettyNIOServer【Netty实现的NIO服务端】

package server;

import handler.ServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * Netty实现的NIO服务端【向客户端读取数据、输出数据】
 *
 * @author 有梦想的肥宅
 * @date 2022/6/3
 */
public class NettyNIOServer {
    public static void main(String[] args) {
        //1、创建服务端启动引导类,用于引导服务端的启动工作
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        //2、创建NioEventLoopGroup对象,作用类似线程组
        NioEventLoopGroup boss = new NioEventLoopGroup();//用于获取链接的线程组
        NioEventLoopGroup worker = new NioEventLoopGroup();//用于获取数据的线程组

        //3、配置服务端启动引导类
        serverBootstrap
                .group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        //PS:这里配置建立连接后的处理逻辑【自定义handler】
                        ch.pipeline().addLast(new ServerHandler());
                    }
                }).bind(8000);
    }
}

ServerHandler【服务端连接处理类】

package handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 服务端连接处理类
 *
 * @author 有梦想的肥宅
 * @date 2022/5/19
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /*PS:channelRead()方法在接收到数据之后会被回调*/
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println("4、【有梦想的肥宅】Server开始接收数据:" + sdf.format(new Date()));

        //1、强转接收到的消息内容
        ByteBuf byteBuf = (ByteBuf) msg;

        //2、在服务端输出接收到的消息内容
        Thread.sleep(1000);
        System.out.println("5、【有梦想的肥宅】Server接收到消息:" + byteBuf.toString(StandardCharsets.UTF_8) + sdf.format(new Date()));

        //3、向服务端输出内容【类似客户的channelActive()方法的操作】
        System.out.println("6、【有梦想的肥宅】server开始回复数据:" + sdf.format(new Date()));
        //3.1 获取二进制抽象ByteBuf对象
        ByteBuf byteBufToClient = ctx.alloc().buffer();
        //3.2 准备数据,并指定字符串的字符集为UTF-8
        byte[] bytes = "【有梦想的肥宅】server回复消息啦~".getBytes(StandardCharsets.UTF_8);
        //3.3 填充数据到ByteBuf对象
        byteBufToClient.writeBytes(bytes);
        //3.4 写数据
        Thread.sleep(1000);
        ctx.channel().writeAndFlush(byteBufToClient);
        System.out.println("7、【有梦想的肥宅】Server回复数据完毕:" + sdf.format(new Date()));
    }

}

四、执行效果和小结

  为了方便小伙伴们查看流程执行状况,我特意做了Thread.sleep(1000),并给输出日志加上了序号和时间,执行效果如下:

  小结如下:

  • 1、Client先连接上了Server,由于我们自定义的ClinetHandler类重写了ChannelInboundHandlerAdapter的channelActive()方法,在连接上服务端时,会去调用此方法
  • 2、执行channelActive()方法,向服务端输出内容
  • 3、又由于我们自定义的ServerHandler类重写了ChannelInboundHandlerAdapter的channelRead()方法,当接收到客户端发来的数据之后会被调用
  • 4、服务端输出接收到的消息内容,并向客户端回复消息
  • 5、我们自定义的ClinetHandler类还重写了ChannelInboundHandlerAdapter的channelRead()方法,能够读取到服务端回复的消息并处理
  • 6、客户端收到服务端回复的消息,并把消息内容打印在控制台上,整个双向通信流程结束。

标签:netty,肥宅,双向通信,Client,io,import,new,服务端
来源: https://www.cnblogs.com/riches/p/16340016.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有