Netty最佳实践之数据通信

Netty最佳实践-数据通信 使用一种特殊的长连接,在指定某一时间之内,服务器与某台客户端没有任何通信,则断开连接。下次连接则是客户端向服务器发送请求的时候,再次建立连接。 阅读详情

使用Netty进行两台或者多台服务器之间的数据通信,大体有以下三种情况:

  1. 使用长连接通道不断开的方式进行通信。也就是服务器和客户端的通道不断开,一直处于开启状态,如果服务器的性能足够好,并且我们的客户端数量足够少的情况下,推荐这种方式。
  2. 一次性批量提交数据,推荐采用短连接方式。即我们可以把数据保存在本地临时缓冲区或者临时表中,当到达一定临界值的时候一次性批量提交,或者是根据定时任务轮询提交,这种方式的弊端是做不到实时性,在对实时性要求不高的应用程序中推荐使用。
  3. 我们可以使用一种特殊的长连接,在指定的一段时间内,服务器与某台客户端么有进行任何通信,则断开连接。下次客户端向服务器端发送请求时再次建立连接,这种模式需要考虑两种因素:

3.1 如何在服务器端和客户端在一定时间超时后关闭通道?关闭通道后如何再建立连接?

答:可以使用Netty的ReadTimeoutHandler,在一定时间内没读取到数据则断开连接;再次建立连接直接发起请求即可。

3.2 客户端宕机时我们无需考虑,下次客户端重启后就可以与服务器建立连接;但是服务器宕机后,我们客户端如何与服务端建立连接?答案无非是隔一段时间轮询建立连接。


以下是设置连接的超时处理,在规定时间内无数据传输则断开,在断开连接后重新建立连接:

server:

public class Server {
 
	public static void main(String[] args) {
		
		EventLoopGroup pGroup = new NioEventLoopGroup();
		EventLoopGroup cGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap b = new ServerBootstrap();
			b.group(pGroup, cGroup)
			 .channel(NioServerSocketChannel.class)
			 .option(ChannelOption.SO_BACKLOG, 1024)
			 // 设置日志
			 .handler(new LoggingHandler(LogLevel.INFO))
			 .childHandler(new ChannelInitializer<SocketChannel>() {
				protected void initChannel(SocketChannel sc) throws Exception {
					// Marshalling的编解码器
					sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
					sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
					// 设置无数据读取的超时处理器
					sc.pipeline().addLast(new ReadTimeoutHandler(5)); 
					// 自定义处理器
					sc.pipeline().addLast(new ServerHandler());
				}
			});
			
			ChannelFuture cf = b.bind(8765).sync();
			
			cf.channel().closeFuture().sync();
		}finally{
			pGroup.shutdownGracefully();
			cGroup.shutdownGracefully();
		}
	}
}

serverhandler

public class ServerHandler extends ChannelHandlerAdapter{

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		Request request = (Request)msg;
		System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " + request.getRequestMessage());
		Response response = new Response();
		response.setId(request.getId());
		response.setName("response" + request.getId());
		response.setResponseMessage("响应内容" + request.getId());
		ctx.writeAndFlush(response);//.addListener(ChannelFutureListener.CLOSE);
	}
 
	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.close();
	}
}

client:

public class Client {
	
	private static class SingletonHolder {
		static final Client instance = new Client();
	}
	
	public static Client getInstance(){
		return SingletonHolder.instance;
	}
	
	private EventLoopGroup group;
	private Bootstrap b;
	private ChannelFuture cf ;
	
	private Client(){
		group = new NioEventLoopGroup();
		b = new Bootstrap();
		b.group(group)
		 .channel(NioSocketChannel.class)
		 .handler(new LoggingHandler(LogLevel.INFO))
		 .handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel sc) throws Exception {
					sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
					sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
					// 超时handler(当服务器端与客户端在指定时间以上没有任何进行通信,则会关闭响应的通道,主要为减小服务端资源占用)
					sc.pipeline().addLast(new ReadTimeoutHandler(5)); 
					sc.pipeline().addLast(new ClientHandler());
				}
	    });
	}
	
	public void connect(){
		try {
			this.cf = b.connect("127.0.0.1", 8765).sync();
			System.out.println("远程服务器已经连接, 可以进行数据交换..");				
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public ChannelFuture getChannelFuture(){
		
		if(this.cf == null){
			this.connect();
		}
		if(!this.cf.channel().isActive()){
			this.connect();
		}
		
		return this.cf;
	}
	
	public static void main(String[] args) throws Exception{
		final Client c = Client.getInstance();
		
		ChannelFuture cf = c.getChannelFuture();
		for(int i = 1; i <= 3; i++ ){
			Request request = new Request();
			request.setId("" + i);
			request.setName("pro" + i);
			request.setRequestMessage("数据信息" + i);
			cf.channel().writeAndFlush(request);
			TimeUnit.SECONDS.sleep(4);
		}
 
		cf.channel().closeFuture().sync();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println("进入子线程...");
					ChannelFuture cf = c.getChannelFuture();
					System.out.println(cf.channel().isActive());
					System.out.println(cf.channel().isOpen());
					
					//再次发送数据
					Request request = new Request();
					request.setId("" + 4);
					request.setName("pro" + 4);
					request.setRequestMessage("数据信息" + 4);
					cf.channel().writeAndFlush(request);					
					cf.channel().closeFuture().sync();
					System.out.println("子线程结束.");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		System.out.println("断开连接,主线程结束..");
	}
}

clienthandler

public class ClientHandler extends ChannelHandlerAdapter{

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try {
			Response resp = (Response)msg;
			System.out.println("Client : " + resp.getId() + ", " + resp.getName() + ", " + resp.getResponseMessage());			
		} finally {
			ReferenceCountUtil.release(msg);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		ctx.close();
	}
	
}

流程分析:

客户端每隔4s钟向服务器端发数据:

ChannelFuture cf = c.getChannelFuture();

for(int i = 1; i <= 3; i++ ){
	Request request = new Request();
	request.setId("" + i);
	request.setName("pro" + i);
	request.setRequestMessage("数据信息" + i);
	cf.channel().writeAndFlush(request);
	TimeUnit.SECONDS.sleep(4);
}

cf.channel().closeFuture().sync();

那么当发完三次数据后,将会断开和服务器端的连接,看打印:

Client打印:

远程服务器已经连接, 可以进行数据交换..
Client : 1, response1, 响应内容1
Client : 2, response2, 响应内容2
Client : 3, response3, 响应内容3
断开连接,主线程结束..

Server打印:

[01:07:14] nioEventLoopGroup-0-0 INFO  [] [] [io.netty.handler.logging.LoggingHandler] - [id: 0xa1a7160d] REGISTERED
[01:07:14] nioEventLoopGroup-0-0 INFO  [] [] [io.netty.handler.logging.LoggingHandler] - [id: 0xa1a7160d] BIND: 0.0.0.0/0.0.0.0:8765
[01:07:14] nioEventLoopGroup-0-0 INFO  [] [] [io.netty.handler.logging.LoggingHandler] - [id: 0xa1a7160d, /0:0:0:0:0:0:0:0:8765] ACTIVE
[01:07:21] nioEventLoopGroup-0-1 INFO  [] [] [io.netty.handler.logging.LoggingHandler] - [id: 0xa1a7160d, /0:0:0:0:0:0:0:0:8765] RECEIVED: [id: 0x076dc15e, /127.0.0.1:61655 => /127.0.0.1:8765]
Server : 1, pro1, 数据信息1
Server : 2, pro2, 数据信息2
Server : 3, pro3, 数据信息3

为了让客户端断开后可以重新连接上,添加以下代码:

new Thread(new Runnable() {
	@Override
	public void run() {
		try {
			System.out.println("进入子线程...");
			ChannelFuture cf = c.getChannelFuture();
			System.out.println(cf.channel().isActive());
			System.out.println(cf.channel().isOpen());
			
			// 再次发送数据
			Request request = new Request();
			request.setId("" + 4);
			request.setName("pro" + 4);
			request.setRequestMessage("数据信息" + 4);
			cf.channel().writeAndFlush(request);					
			cf.channel().closeFuture().sync();
			System.out.println("子线程结束.");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}).start();

开启一个线程重新获取channelFuture:

public ChannelFuture getChannelFuture(){
	
	if(this.cf == null){
		this.connect();
	}
	if(!this.cf.channel().isActive()){
		this.connect();
	}
	
	return this.cf;
}

于是客户端继续向服务器发送第四次数据:
这里写图片描述
服务端:
这里写图片描述

使用 Netty 搭建消息中心 简介: Netty 是一套异步事件驱动的网络应用程序框架,支持快速开发可维护、高性能、面向协议的服务器和客户端。Netty 中涵盖包括网络通讯、多线程处理和并发等多个领域的专业知识,并优雅的将这些知识组织和处理。重要 本例中,所有消息处理均采用模拟处理方式,不涉及实际实现!!!基础概念: Netty 中的几个基础知识点 选择器 Channel EventLoop 回调 Future 事件和 C 阅读详情

相关推荐

描述,设计,编程的最佳实践

过去一年,都对开发方式做了持续跟踪,不停的记录,复盘,调整做法。 可以得出结论,最佳实践就是坚持简单完备的实践,把事情做全,可以在长期的时间段里达到最好的质量,效率,这里包括: 需求和说明文档(包括需求文档和工具功能的说明文档) 代码持续积累,达到符合需求的程度,并且达到心意相合的程度 测试根据需求的关键点,做好测试 就这么简单。 不能实行的原因 在于我们缺少严谨复盘的习惯,那么根据人的感觉...

安柏霖的专栏 643

Netty学习一——Netty的通信原理

在 Linux 的网络编程这个层次中,客户机和服务器各有一个Socket文件,当两台主机通信时,客户机里的客户端应用进程 A 发送消息,通过 TCP协议数据包头的 SYN 标志位置1,进行主动打开,经 A 主机的 TCP/IP 协议栈发送到 LAN,然后经 WAN 中的路由器传给服务端应用进程 B 的目的主机所在的 LAN,之后经目的主机的 LAN 将报文传给目的主机,最后经目的主机的 TCP/IP 协议栈处理,服务器被动打开,将消息递交给目的应用程序 B。下面的 demo 只一次调用,很简单。

yx444535180的专栏 1565

Netty框架与ProtoBuf高效数据通信实践

本文还有配套的精品资源,点击获取 简介:在分布式系统和网络通信中,数据序列化和反序列化的效率至关重要。ProtoBuf是一种由Google开发的轻量级、快速且语言无关的数据序列化协议,而Netty是一个高性能的网络应用框架,用于构建可伸缩的服务端应用。本文深入探讨了如何利用Netty框架发送ProtoBuf格式的数据,并提供了在Netty中实现ProtoBuf的编码解码器、...

weixin_26907223的博客 1249

SpringBoot+Netty 结合物联网通信 加入WebSocket协议(2)

目录接上文编写WebSocket处理器类第二编写WebSocket 编解码器第三 在上文Netty服务端加入WebSocket 接上文 SpringBoot+Netty 结合物联网初步开发搭建 共享硬件+手机APP+电脑通信(1) 上文做到了设备连接上服务器端 服务器对报文进行解析。存取数据等操作。 我们这边手机APP采用了WebSocket协议 所以我们Netty服务器要加入WebSocket协议进行解析接收。 下文就是在Netty服务端接入WebSocket协议 编写WebSocket处理器类 这边先编

weixin_44204411的博客 2202

物联网netty服务端和客户端两个项目

物联网Netty服务端,接收多设备发送协议报文,处理粘包;客户端监听服务端数据,保证客户端断联后进行重连,实现高可用

Rust 编译工具链配置指南:从 link.exe 缺失到完美解决

本文详细解析了Windows下Rust编译时常见的'link.exe not found'错误,提供了MSVC和MinGW-w64两种工具链的完整配置指南。从Visual Studio组件安装到环境变量设置,再到疑难排查技巧,帮助开发者彻底解决Rust编译工具链配置问题,提升开发效率。

earth的博客 318

netty最佳实践之数据通信(转载)

一、背景描述 使用Netty进行两台或者多台服务器之间的数据通信,大体有以下三种情况: 使用长连接通道不断开的方式进行通信。也就是服务器和客户端的通道不断开,一直处于开启状态,如果服务器的性能足够好,并且我们的客户端数量足够少的情况下,推荐这种方式。 一次性批量提交数据,推荐采用短连接方式。即我们可以把数据保存在本地临时缓冲区或者临时表中,当到达一定临界值的时候一次性批量提交,或者是根据定时任务...

uzong 965

用LTspice仿真Buck电路输出电容:从参数计算到波形优化的全流程演示

本文详细介绍了使用LTspice仿真Buck电路输出电容的全流程,从理论计算到波形优化。通过解析关键参数如纹波电压、瞬态响应和ESR,结合工程计算方法和LTspice仿真技巧,帮助工程师优化Buck电路设计,解决输出纹波过大和瞬态响应不佳的问题。

night的博客 851

NIO(九)--Netty最佳实践--实际场景一--数据通信

                 

csdn_kenneth的博客 666

Matlab实战:用DQN算法让机器人学会自主避障(附完整代码)

本文详细介绍了如何使用Matlab实现DQN(深度Q网络)算法,使机器人在复杂环境中学会自主避障。通过环境建模、网络架构设计、奖励函数优化及实战调试,提供了完整的代码实现和训练策略,帮助开发者快速应用于机器人路径规划项目。

t8u9v0w1x的博客 232

基于 parallels ubuntu 20.04 LTS (focal) 的ros+px4+gazebo 安装

基于 parallels ubuntu 20.04 LTS (focal) 的ros+px4+gazebo 安装。

weixin_40132006的博客 2240

网络编程--(八)Netty最佳实践-数据通信

我们可以使用一种特殊的长连接,在指定的时间之内,服务器与某台客户端没有任何通信,则断开连接。下次连接则是客户端向服务器发送请求的时候,再次连接,但是这种模式我们需要考虑2个因素:1.如何在超时(即服务器和客户端没有任何通信)后关闭通道?关闭通道后我们又如何再次建立连接?2.客户端宕机时,我们无需考虑,下次客户端重启之后我们就可以与服务器建立连接,但是服务器宕机时,我们的客户端如何与服务器进行连接呢...

superviser3000的博客 284

【实验】Linux下完全卸载oracle单实例(亲身体验完整版)

停止oracle数据库服务 停止监听 卸载数据库实例 因为自己懒得再弄dbca图形化界面啥的,直接采用dbca静默删除数据库实例,命令如下 dbca -silent -deleteDatabase -sourcedb orclhq -sid orcl -sysDBAUserName orcl -sysDBAPassword zte [oracle@slave ~]$ dbca -silent ...

萝卜吃鱼914的博客 1945

网络编程之每天学习一点点[day11]-----netty最佳实践之数据通信

使用Netty进行两台或者多台服务器之间的数据通信,大体有以下三种情况:1 使用长连接通道不断开的方式进行通信。也就是服务器和客户端的通道不断开,一直处于开启状态,如果服务器的性能足够好,并且我们的客户端数量足够少的情况下,推荐这种方式。2 一次性批量提交数据,推荐采用短连接方式。即我们可以把数据保存在本地临时缓冲区或者临时表中,当到达一定临界值的时候一次性批量提交,或者是根据定时任务轮询提交,这...

723

SVN使用:使用TortoiseSVN遇到提示请执行“清理”命令的解决方法

作为程序员来说,在团队开发过程中关于代码管理的工具使用并不陌生,比较常用的代码合并管理工具如:Git、SVN等,虽然相关工具的使用并不复杂,但是还是要掌握常用的使用方法,尤其是相关的第三方软件的使用也是极为重要的,而且有时候使用这些三方软件来进行代码管理的时候也会遇到一些问题。本篇博文就来分享一下在SVN使用的时候使用TortoiseSVN遇到提示请执行“清理”命令的解决方法,方便查阅使用。

全沾软贱开发攻城狮 1万+

29、高速低功耗采样保持放大器设计

本文详细介绍了适用于低功耗模数转换器的高速低电压采样保持放大器(SHA)的设计技术,包括传统SHA的局限性、采样技术分类以及全NPN型和BiCMOS型SHA的具体设计实现。同时,文章深入探讨了优化输入电容、采样开关驱动及低功耗设计等具体措施,并提供了10位ADC前端和无线通信应用中的实例分析,为相关领域的工程师提供有价值的参考。

weixin_30600615的博客 424

Netty——基本使用介绍

http://blog.youkuaiyun.com/haoyuyang/article/details/53243785 1.为什么选择Netty 上一篇文章我们已经了解了Socket通信(IO/NIO/AIO)编程,对于通信模型已经有了一个基本的认识。其实上一篇文章中,我们学习的仅仅是一个模型,如果想把这些真正的用于实际工作中,那么还需要不断的完善、扩展和优化。比如经典的TCP读包写包问题

guolong1983811的专栏 368

基于风机和水轮机互补发电系统的Simulink仿真

随着全球对清洁能源的需求不断增长,风力发电和水力发电作为两种重要的可再生能源发电方式,受到了广泛关注。风机和水轮机互补发电系统结合了两者的优势,能够在不同的自然条件下稳定地输出电能,提高能源利用效率和供电可靠性。本文将详细介绍风机和水轮机互补发电的原理,包括风力发电原理、水力发电原理以及两者互补的机制和优势,并通过相关数学公式进行深入分析。水轮机也有其特定的特性曲线,包括流量 - 水头曲线、功率 - 流量曲线等。在不同的水头和流量条件下,水轮机的输出功率会发生变化。

平时工作较为繁忙,私信消息一般晚上回复,谢谢大家~~ 167

Netty—基本使用介绍

1.为什么选择Netty 上一篇文章我们已经了解了Socket通信(IO/NIO/AIO)编程,对于通信模型已经有了一个基本的认识。其实上一篇文章中,我们学习的仅仅是一个模型,如果想把这些真正的用于实际工作中,那么还需要不断的完善、扩展和优化。比如经典的TCP读包写包问题,或者是数据接收的大小,实际的通信处理与应答的处理逻辑等等一些细节问题需要认真的去思考,而这些都需要大量的时间和经历,以及

bwh0520的博客 234

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Netty(四)之数据通信的三种方式

三种数据通信方式 我们需要了解在真正项目中如何去考虑Netty的使用,我们需要考虑的问题是两台机器(甚至多台)使用Netty怎么进行通信,大体上分为三类。 第一种:长连接 使用长连接通道不断开的形式进行通信,也就是服务器和客户端的通道一直处于开启状态,如果服务器的性能足够好,并且我们的客户端数量也比较少的情况下,我还是推荐这种方式。 第二种:短连接 一次性批量提交数据采用短连接方式。也就是我...

CBeann的博客 3522

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

亲测!超详细的使用netty进行tcp数据通信的流程,附带完整的源代码

超详细

小红的成长日记 4565

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

java网络编程之Netty实战数据通信(七)

java网络编程之Netty实战数据通信(七)

hfbin的博客 5399

Netty之数据通信和心跳检测(四)

1、Netty数据通信的场景    1.1在实际场景中,我们使用Netty进行通信大致有以下3种方式:        第一种,使用长连接通道不断开的形式进行通信,也就是服务器和客户端的通道一直处于开启的状态。如果服务器性能足够好,并且我们的客户端数量也比较少的情况下,是适合使用长连接的通道。        第二种,采用短连接方式,一次性批量提交数据,也就是我们会把数据保存在本地临时缓冲区或者临时表...

99708 631

Java网络编程(9) - Netty怎么做数据通信?Netty的心跳检测怎么实现?Netty怎么用Http协议通信?

Netty实际案例的考虑 – 数据通信实现 1、长链接:使用长链接通道不断开的形式进行通信,也就是Server和Client的通道一直处于开启状态,如果服务器性能足够好,并且我们的客户端数据也比较少的情况下,可以使用这种。 2、一次性批量提交数据:这是采用短链接方式,也就是会把数据保存在本地临时缓冲区或者临时表里,当达到临界值时,进行一次性批量提交,又或者根据定时任务轮询提交,这种情况的弊端是做不到实时性传输,在对实时性不高的应用程序可以使用这种。 3、特殊的长链接...

Su_Levi_Wei的博客 541

Netty数据通信和心跳检测

一、数据通信 我们需要考虑的问题是两台机器使用Netty的怎么进行通信,大体上可以分为三种:  1、使用长连接通道不断开的方式进行通信,也就是客户端和服务器端的通道一直处于开启状态,客户端数量较少的情况下,可以使用这种方式 2、一次性批量提交数据,采用短连接的方式。也就是我们会把数据保存在本地临时目录下或者临时表里面,当达到临界值的时候一次批量提交数据,又或者根据定时的任务轮询提交。这种情况

u010634288的博客 3773

Spring Boot 整合 Netty和Protobuf

前言 本篇文章主要介绍的是SpringBoot整合Netty以及使用Protobuf进行数据传输的相关内容。Protobuf会简单的介绍下用法。 介绍 protocol buffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和python,每一种实现都包含了相应语言的编译器以及库文件。 ...

luoqinglong的专栏 1145
上一篇: Netty之 ChannelPipeline 和 ChannelHandler
下一篇: Maven+Tomcat实现热部署
章 鱼
博客等级 码龄10年 203粉丝 105原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值