工作上有转发程序,从一个客户端发送数据到转发程序再发送到另一个服务端。整个传输协议是基于交通部809协议要求的。

809协议文档:()

目录

问题1:怎么关闭链路

问题2:当链路无故关闭,怎么重连

问题3:关于主从链路之间的链路保持请求


遇到的主要问题如下:

问题1:怎么关闭链路

netty中有两个关于通道的关闭方法,一个是断开连接  channel.disconnect() 一个是关闭通道 channel.close()

根据网上资料 close()方法中会先去检测链路是否畅通,然后执行channeldisconnect方法 最后统一执行channelClosed的方法

(可以看看这个大佬写的:)

现在有个问题环境:两个客户端同时连到我的服务端,并且同时发送相同的一条809协议的1001主链路请求数据,我只需要一个客户端连我,并且是后面连接到我客户端进行一个保存,然后将前面的客户端通道给断掉。

解决方法如下:

在start启动类中创建了一个key 为ip channel 为value 的map 然后通过每次客户端去连接服务端时,将当前channel记录,如果ip相同,就把上一个ip的channel给断掉

如下进行实现的:
 一个Start类,主要是记录一些成员变量和常量, 这里记录了address(ip+port),ip地址, 一个存放channel的map,放在这里是为了防止每次有客户端连接服务器,会new一个handler的问题,放在handler中的话就不能记录每次来的ip和channel。所以放在这个类里面。

public class Start{
   
	// 存放ip地址和channel
	public static Map<String, Channel> checkMap = new HashMap<>();

    public static void initServerChannel(){}
    public static void initClientChannel(){}
    public static void main(){}   
     ......
}

然后在serverHandler中需要去创建一个方法,去判断需要怎么去断开连接。写了如下一个方法,就是来一条连接将其存到map,

如果有新的客户端连接,那么就需要把当前的channel 也就是存储在map里的channel关掉,然后将新的channel存入到map当中

void tocheckActive(Channel channel) {

		String socket = channel.remoteAddress().toString().trim();
		System.out.println("当前Address地址为: " + socket);
		int index = socket.indexOf(":");
		String sockets = socket.substring(1, index).trim();
		System.out.println("当前Ip地址为:" + sockets);

		if (Start.checkMap.size()==0) {
			Start.checkMap.put(sockets, channel);
			System.out.println("当前map为空,存入channel");

		} else {

			if (Start.checkMap.containsKey(sockets)) {
				// 匹配上了。断掉map中的channel,再将其新的channel放入
				System.out.println("新连的链路与当前链路是一个ip,断掉当前链路...");
				Start.checkMap.get(sockets).disconnect();
				Start.checkMap.get(sockets).close();
				try {
					Thread.sleep(1500L);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("存入新链路...");
				Start.checkMap.put(sockets, channel);

			}
		}

在serverHandler中使用这个方法,再执行channelActive方法后的内容

@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {

		    tocheckActive(ctx.channel());

			System.out.println("准备连接");
			Connection.checkMap.clear();

}

例子:

启动服务器,先启动一个客户端连接

Java netty 服务器端主动断开链接 netty 断开连接_System

然后在去启动第二个客户端,会将第一个客户端关闭,然后第二个连接

Java netty 服务器端主动断开链接 netty 断开连接_System_02

这个就是去保证如果两个客户端一次性连接 而服务器只需要最新的那个客户端的连接链路的方法

问题2:当链路无故关闭,怎么重连

问题环境:如果连接的客户端断开了,那么按照正常情况需要重新连接

我这个处理的流程是

1.channelInactive方法是针对链路断开后走的方法,这个时候需要将链路去断开,使用disconnect方法去让链路取消连接

@Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
	
		System.out.println("当前链路断开..");
		//System.out.println("ctx.disconnect:"+ctx.disconnect());
			ChannelFuture future = ctx.disconnect();
			System.out.println("future:"+future);
			
		if(future.isSuccess()){
			ctx.channel = null;
			reconn();
		}
		
    }

如果断开是成功的,那么去走客户端重连方法,这个时候需要注意的是基于809协议的重连方法,需要在链路重新建立起连接后发送1001的链路请求连接的数据,

所以我的重连方法是如下:

public static void reconn() {

try {
bootStrap.connect(Address,Port).addListener(
new ChannelFutureListener() {
@Override
	public void operationComplete(ChannelFuture future) throws Exception {
	if (!future.isSuccess()) {
		System.out.println("连击失败了");
		final EventLoop loop = future.channel().eventLoop();
		System.out.println("等待链接");
		loop.schedule(new Runnable() {
		  @Override
		  public void run() {
			System.out.println("开始重连");
			 reconn();
		  }
	    }, 3L, TimeUnit.SECONDS);
       } else {
		SXclientChannel = future.channel();
		System.out.println("链接成功...");
		Thread.sleep(1000L);
		System.out.println("1001数据再次发送");
		future.channel.writeAndFlush(Input1001).addListener(new ChannelFutureListener() {
            @Override
			public void operationComplete(ChannelFuture future)throws Exception {
			if (!future.isSuccess()) {
			System.out.println("1001数据发送失败");
			}
		   }
	     });
       }		
  	 }
   });
} catch (Exception e) {
			e.printStackTrace();
			System.out.println("连接出现错误" + e.getMessage());

			// future.channel().closeFuture().sync();
		}

	}

就是先用connect方法去连接,启动一个监听,如果成功了就用这条链路发送数据 如果失败了,就是用Eventloop去循环等待执行recon方法,直到连接成功。(有点递归的味道)

就像如下:

Java netty 服务器端主动断开链接 netty 断开连接_System_03

当前模拟的服务端是被连接了。

然后连接成功的数据发送1001数据

Java netty 服务器端主动断开链接 netty 断开连接_链路_04

如果这个时候我把主链路的7100端口断掉,那么他会重连并且发送1001数据,如果服务器异常关闭很久,主链路应该一直等待连接

Java netty 服务器端主动断开链接 netty 断开连接_809交通部协议_05

我将监听停掉,模拟服务出现故障一直不能连接,现在就是等待连接的状态

Java netty 服务器端主动断开链接 netty 断开连接_客户端_06

然后我打开监听,这样就能够又连上了

Java netty 服务器端主动断开链接 netty 断开连接_netty_07

问题3:关于主从链路之间的链路保持请求

这个是netty心跳加上809协议要求链路畅通

netty有一个长连接,在初始化通道的时候需要打开 keepAlive 。然后定时发送心跳,让链路畅通。结合890协议需要主链路来回传递1005、1006数据。从链路来回传递9005 和9006数据

boootStrap.group().option(ChannelOption.SO_KEEPALIVE, true)

数据传输按一定时间就要发送链路保持畅通数据

Java netty 服务器端主动断开链接 netty 断开连接_System_08