欢迎阅读本篇文章

提示:本文只是提供部分核心代码,源码详见代码示例

使用Netty实现客户端和服务端之间的双向通信

  • 前言
  • 一、服务端
  • 二、客户端

前言

在上个月的开发计划中,有一个系统控制喇叭播放的功能。当时就想到了使用netty进行通信操作。于是在调研途中,发现网上写的都是简单案例,不适用于当前的复杂通信模式。比如:超时断线,断线重连,通信监听,错误记录存储,以及断线和上线后的钉钉通知等等。所以自己从头到尾重新写了一个完整项目,供大家参考。


提示:以下是本篇文章正文内容,下面案例可供参考

一、服务端

在netty的通讯服务中,需先启动服务端,提供自身的端口和IP供客户端连接。

代码如下(示例):

@Slf4j
public class NettyServer {public Result bind(int port) throws Exception {try {EventLoopGroup bossGroup = new NioEventLoopGroup(); //bossGroup就是parentGroup,是负责处理TCP/IP连接的EventLoopGroup workerGroup = new NioEventLoopGroup(); //workerGroup就是childGroup,是负责处理Channel(通道)的I/O事件ServerBootstrap sb = new ServerBootstrap();sb.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128) //初始化服务端可连接队列,指定了队列的大小128.childOption(ChannelOption.SO_KEEPALIVE, true) //保持长连接.childHandler(new ChannelInitializer<SocketChannel>() {  // 绑定客户端连接时候触发操作@Overrideprotected void initChannel(SocketChannel sh) throws Exception {sh.pipeline().addLast(new RpcDecoder(RpcRequest.class)) //解码request.addLast(new RpcEncoder(RpcResponse.class)) //编码response//readerIdleTime:读超时时间;  writerIdleTime:写超时时间; allIdleTime:所有类型超时时间;//.addLast(new IdleStateHandler(10, 10, 10, TimeUnit.SECONDS)).addLast(new ServerHandler()); //使用ServerHandler类来处理接收到的消息}});//绑定监听端口,调用sync同步阻塞方法等待绑定操作完成,完成后返回ChannelFuture类似于JDK中FutureChannelFuture future = sb.bind(port).sync();log.info("服务端绑定端口:"+port+"成功!");if (future.isSuccess()) {log.info("服务端启动成功");List<ChannelFuture> channelFuture = ServerHandler.getChannelFuture();channelFuture.add(future);List<EventLoopGroup> eventLoopGroup = ServerHandler.getEventLoopGroup();eventLoopGroup.add(workerGroup);eventLoopGroup.add(bossGroup);} else {log.error("服务端启动失败");future.cause().printStackTrace();bossGroup.shutdownGracefully(); //关闭线程组workerGroup.shutdownGracefully();return Result.ERROR_INFO("Netty服务端启动失败失败!");}//成功绑定到端口之后,给channel增加一个 管道关闭的监听器并同步阻塞,直到channel关闭,线程才会往下执行,结束进程。future.channel().closeFuture().sync();}catch (Exception e){e.printStackTrace();}return Result.ERROR_INFO("Netty服务端发送消息成功!");}/* public static void main(String[] args) throws Exception {//启动server服务new NettyServer().bind(9999);}*/
}

在上面的代码示例中,最重要的就是 ServerHandler 方法。继承ChannelInboundHandlerAdapter。实现 channelActive(有客户端连接服务器会触发此函数) channelInactive(有客户端终止连接服务器会触发此函数)等一些方法。一些的读操作时捕获到异常就可以调用 exceptionCaught()。更具体详细内容可以自行查阅。但是我的代码示例中已经基本包含了所需用到的方法,大家可以下载后可以看一看。

特别提醒:
在上面的服务端代码中,使用了 ChannelFuture future = sb.bind(port).sync()【绑定监听端口,调用sync同步阻塞方法等待绑定操作完成,完成后返回ChannelFuture类似于JDK中Future】。所以项目如果使用了启动就开启服务端,那么一定要加线程池进行操作,要不然项目就会卡在不动无法完成启动。

 log.info("开始启动预加载服务");if (contextRefreshedEvent.getApplicationContext().getParent() == null) {try {log.info("项目启动,开启Netty服务!");new Thread(() -> {try {new NettyServer().bind(configProperties.getNettyServerPort());} catch (Exception e) {e.printStackTrace();}}).start();} catch (Exception e) {log.error("项目启动时,Netty服务开启失败!");e.printStackTrace();}}

二、客户端

启动好服务端以后,开始启动客户端

代码如下(示例):

@Slf4j
public class NettyClient {private final String host;private final int port;//连接服务端的端口号地址和端口号public NettyClient(String host, int port) {this.host = host;this.port = port;}private volatile Channel clientChannel;Bootstrap bootstrap;EventLoopGroup group;public void start() {group = new NioEventLoopGroup();//创建客户端启动对象,注意客户端使用的不是ServerBootStrap而是BootStrapbootstrap = new Bootstrap();ChannelFuture future;  //ChannelFuture的作用是用来保存Channel异步操作的结果try {bootstrap.group(group).channel(NioSocketChannel.class)  // 使用NioSocketChannel来作为连接用的channel类.handler(new ChannelInitializer<SocketChannel>() { // 绑定连接初始化器@Overridepublic void initChannel(SocketChannel ch) throws Exception {System.out.println("正在连接服务端中...");ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new RpcEncoder(RpcRequest.class)); //编码requestpipeline.addLast(new RpcDecoder(RpcResponse.class)); //解码response// 3s 内如果没有向服务器写数据,会触发一个 IdleState#WRITER_IDLE 事件  用来判断是不是 读空闲时间过长,或 写空闲时间过长//readerIdleTime:读超时时间;  writerIdleTime:写超时时间; allIdleTime:所有类型超时时间;//pipeline.addLast(new IdleStateHandler(10, 10, 10, TimeUnit.SECONDS));pipeline.addLast(new ClientHandler(new NettyClient(host, port)));}});//发起异步连接请求,绑定连接端口和host信息future = bootstrap.connect(host, port).sync();//添加重连测试ClientHandler.getBootstrap().put("nettyServer",bootstrap);future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture arg0) throws Exception {if (future.isSuccess()) {System.out.println("连接服务器成功");List<ChannelFuture> channelFuture = ClientHandler.getChannelFuture();channelFuture.add(future);List<EventLoopGroup> eventLoopGroup = ClientHandler.getEventLoopGroup();eventLoopGroup.add(group);} else {System.out.println("连接服务器失败");future.cause().printStackTrace();group.shutdownGracefully(); //关闭线程组throw new BizException(500,"连接Netty服务器失败",null);}}});future.channel().closeFuture().sync();}catch (Exception e){e.printStackTrace();log.error("客户端启动失败!服务端不在线!", e);throw new BizException(500,"客户端启动失败!服务端不在线!"+e,null);}}

特别提醒:
若有时候真的忘记了先启动服务端怎么办呢,问题不大!在代码中我已经做了重连机制。使用线程池在规定的时间间隔中,循环进行尝试重连。

new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {try {new NettyClient(monitorIp, monitorPort).start();  //启动netty}catch (BizException e){if (e.getErrorMsg().contains("服务端不在线")){log.error("--------------------------error----------------------->"+e.getErrorMsg());//连接异常  服务端没有开启 进行重新连接DingDingSendUtil.postSend("客户端自启动失败!Netty服务端不在线!请检查服务!");new ClientHandler(new NettyClient(monitorIp, monitorPort)).initScheduledExecutor(null);}e.printStackTrace();throw new BizException(500,"Netty客户端【KHD_ONE】,启动异常!"+e.getMessage(),null);}}},"NettyServer").start();

Netty通信的服务就是这么多内容,核心都在 ClientHandler 和 ServerHandler 中,剩下的是一些通过TCP与喇叭进行通信的内容了。有兴趣的也可以看看如何进行操作。这个功能模块基本上用了一个月时间完成,使用到了异步通信,多线程与线程池,TCP通信,定时任务等等。毕竟花了很多心血,已经部署上线可靠运行。有兴趣的朋友可以加QQ:1051266367 找博主要源码。

使用Netty实现客户端和服务端之间的双向通信相关推荐

  1. 一篇文章带你了解https是如何做到客户端与服务端之间安全通信

    https是什么. 超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,常称为HTTP over TLS,HTTP over SSL或HT ...

  2. 【Android 开发】: Android客户端与服务端之间使用JSON交互数据。

    在前面的两讲中,我们讲解了JSON数据格式的一些基本知识,以及做一些小Demo,这一讲我们在前面的基础上来做一个综合的可扩展的Demo,主要是针对Android客户端解析服务端传递过来的JSON数据. ...

  3. python实现socket编程,客户端和服务端之间互相对话(二)

    首先运行服务端,处于监听状态: 最后运行客户端,就可以实现服务端和客户端之间互相发送消息. 客户端: import os import cv2 import socketremote_IP='127. ...

  4. [JAVA]递归实现客户端与服务端之间的文件与文件夹传输

    JAVA实现文件与文件夹传输 声明 其他方法 客户端: 服务端: 声明 本代码的文件夹传输并非完全由本人完成,本人只是在实现递归的基本思想上,稍微处理与改动了原作者的代码的结构,从而实现了文件与文件夹 ...

  5. 超详细,简单用socket建立客户端与服务端之间的通信

    socket,一种通用的网络编程接口,它是一个特殊的文件描述符. 有三种类型: 接流式套接字(SOCK_STREAM):提供了一个面向连接.可靠的数据传输服务,数据无差错.无重复的发送且按发送顺序接收 ...

  6. python中使用socket编程实现带有界面的客户端向服务端发送文件和下载文件

    一主界面: **二:发送文件界面:**首先需要开启发送文件服务端(这里需要注意的是每一次发送文件之前都需要开启一次服务端,因为我在这里将每一次发送文件之后就关闭了客户端和服务端之间的连接) 输出相关客 ...

  7. php socket 握手,python Socket之客户端和服务端握手详细介绍

    这篇文章主要为大家详细介绍了python Socket之客户端和服务端握手,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 简单的学习下利用socket来建立客户端和服务端之间的连接并且发送数据 1 ...

  8. 【学习笔记】在windows下进行基于TCP的本地客户端和服务端socket通信

    文章目录 socket介绍 java中使用socket 基于tcp的socket通信 使用ServerSocket类创建一个web服务器:(java) windows下的基于tcp的socket编程( ...

  9. 验证客户端和服务端可以传输经SM4加密的密文数据,从而验证发送数据已使用服务器密码机进行SM4加密,而不是随便的字符串乱码

    前提操作 搭建客户端和服务端  Socket代码实现服务端 和 客户端之间通信_CHYabc123456hh的博客-CSDN博客 使用wireshark进行数据的监听和测试https://blog.c ...

最新文章

  1. 一起学习阿里巴巴数据中台实践!首次公开!
  2. ES等待任务——是master节点上的task任务
  3. 第一篇JavaScript基础
  4. html5 判断分享,好程序员HTML5大前端分享之函数篇
  5. Java Web学习总结(41)——Java EE 8 新功能展望
  6. iostat命令简单使用
  7. JSpider(4):Tasks,EventsVisitors
  8. SolrCloud集群的安装使用以及Zookeeper的介绍
  9. 静态成员常量的初始化
  10. 温故知新 —— Floyd算法
  11. 菜鸟学开店—电子称连接标签打印机
  12. ReactiveSwift源码解析(二) Bag容器的代码实现
  13. 双向lstm-crf源码的问题和细微修改
  14. WLAN/WIFI信道列表 2020-11-23
  15. 微信小程序的家校通系统(家校联系)
  16. 世间最珍贵的... (外一篇)
  17. 华为od统一考试B卷【分积木】C++ 实现
  18. Adobe软件试用下载
  19. 如何写简单的linux脚本
  20. Unity3D-打飞碟小游戏

热门文章

  1. 二叉树中序遍历Stack实现
  2. 中国慈展会谱写“扶贫三部曲”
  3. 基于jsp+ssm+mysql实现简单的物流快递管理系统
  4. OPPO打开root后宫,oppo手机如何打开root权限
  5. 群集共享卷建文件服务器,在故障转移群集中使用群集共享卷
  6. 论文管理系统项目创建及登录
  7. 小程序图片转换Base64格式的三种方法
  8. vivoy73s和oppoa11哪个好 vivoy73s和oppoa11哪个更值得入手
  9. Shell函数知识点大全
  10. 合并图层和拼合图稿,锁定与解锁图层,显示与隐藏图层,剪切蒙版,了解图层样式面板,创建图形样式,编辑图形样式