006 netty实践_数据通信

        实践生产环境中netty如何使用,项目应用如何去考虑Netty的使用,大体上对于一些参数设置都是根据服务器性能决定,这个不是最主要;

数据通信

        需要考虑的问题是生产环境中两台(多台)服务器之间使用Netty是怎样进行通信,我个人大体上把他分为三种:

        第一种,使用长连接通道不断开的形式进行通信,也就是服务器和客户端的通道一直处于开启状态,如果服务器性能足够好,并且我们的客户端数量也比较少(万以下的长连接基本不会有影响)的情况下,还是推荐这种方式;
        第二种,一次性批量提交数据,采用短连接方式。也就是会把数据保存在本地临时缓冲区或者临时表里,当达到临界值时进行一次性批量提交,又或者根据定时任务轮询提交,这种情况弊端是做不到实时性传输,在对实时性不高的应用程序中可以推荐使用。
        第三种(主流推荐),可以使用一种特殊的长连接,在指定某一时间之内,服务器与某台客户端没有任何通信,则断开连接;下次连接则是客户端向服务器发送请求的时候,再次建立连接;但是这种模式需要考虑2个因素:
-1 如何在超时(即服务器和客户端没有任何通信)后关闭通道?关闭通道后又如何再次建立连接?

设置60秒极限阈值,60秒服务器与客户端午通信就将通道断开(类似连接池机制),下一次客户端有新数据在发起一次新的链接;
-2 客户端宕机时,无需考虑,下次客户端重启之后我们就可以与服务器建立连接,但是服务器宕机时,客户端如何与服务器进行连接呢?

客户端宕机下次重启后会再与服务器建立连接;客户端底层轮询机制,在周期内客户端主动查看服务器状态,并尝试建立连接;

package com.cc.netty.best.runtime;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

public class Server {

	public static void main(String[] args) throws Exception{
		
		EventLoopGroup pGroup = new NioEventLoopGroup();
		EventLoopGroup cGroup = new NioEventLoopGroup();
		//AbstractNioSelector 关于reactor模型
		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 {
				sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
				sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
				sc.pipeline().addLast(new ReadTimeoutHandler(5));//超时handler,阀值5秒
				sc.pipeline().addLast(new ServerHandler());
			}
		});
		ChannelFuture cf = b.bind(8765).sync();
		
		cf.channel().closeFuture().sync();
		pGroup.shutdownGracefully();
		cGroup.shutdownGracefully();
		
	}
}
package com.cc.netty.best.runtime;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

import java.util.concurrent.TimeUnit;


/** 单例
 * Best Do It --- 可以尝试enum创建单例模式
 */
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));//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();
		}
	}
	/** 获取ChannelFuture方法
	 *  1 当前cf为空就调用connect()重新连接
	 *  2 当前cf不可用就connect()重新连接
	 *  3 存活可用直接返回
	 */
	public ChannelFuture getChannelFuture(){
		if(this.cf == null){
			this.connect();
		}
		if(!this.cf.channel().isActive()){
			this.connect();
		}
		return this.cf;
	}
	/**
	 * 关闭客户端应用
	 * @throws InterruptedException
	 */
	public void close() throws InterruptedException{
		this.cf.channel().closeFuture().sync();
		this.group.shutdownGracefully();
	}
	
	public static void main(String[] args) throws Exception{
		final Client c = Client.getInstance();//单例创建
		c.connect();//创建连接,建立通信通道
		
		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);//每写出一条数据等待4秒钟
		}
		/** 发送3次消息循环结束,5秒后触发超时Handler_ReadTimeoutHandler(5),
		 *  -通信断开,通道被关闭,但客户端应用未关闭;
		 */
		//c.close();//调用close()关闭客户端应用
		
		/** 启动一个子进程,在客户端应用未关闭下重新发起通信
		 * -发送第4条数据
		 */
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					TimeUnit.SECONDS.sleep(3);
					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("子线程结束.");
					//c.close();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
	
		
	}
	 
	
	
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值