Netty4(三)多连接客户端设计与实现

本文介绍多连接的netty客户端设计

目标

Netty(二)一文中实现了单连接客户端,也就是说客户端只有一个连接,这就不利于高并发RPC的设计,本文尝试设计一个多连接的客户端,支持断线重连

UML类图

mutilClient.png

实现

多连接客户端

package com.mym.netty.client;


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多连接客户端
 */
public class MutilClient {

    /**服务类*/
    private Bootstrap bootstrap = new Bootstrap();

    /**会话集合*/
    private List<Channel>  channels = new ArrayList<Channel>();

    /**引用计数*/
    private final AtomicInteger index = new AtomicInteger();

    /**初始化*/
    public void init(int count){
        //worker
        EventLoopGroup worker = new NioEventLoopGroup();

        //设置工作线程
        this.bootstrap.group(worker);

        //初始化channel
        bootstrap.channel(NioSocketChannel.class);

        //设置handler管道
        bootstrap.handler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel channel) throws Exception {
                channel.pipeline().addLast(new StringDecoder());
                channel.pipeline().addLast(new StringEncoder());
                channel.pipeline().addLast(new ClientHandler());
            }
        });

        //根据连接数建立连接
        for(int i = 0;i < count;i++){
            ChannelFuture channelFuture = bootstrap.connect("0.0.0.0",9099);
            channels.add(channelFuture.channel());
        }

    }

    /**获取channel(会话)*/
    public Channel nextChannel(){
        return getFirstActiveChannel(0);
    }

    private Channel getFirstActiveChannel(int count) {
        Channel channel = channels.get(Math.abs(index.getAndIncrement() % channels.size()));
        if(!channel.isActive()){
            //重连
            reconect(channel);
            if(count > channels.size()){
                throw new RuntimeException("no Idle channel!");
            }

            return getFirstActiveChannel(count + 1);
        }
        return channel;
    }

    /**重连*/
    private void reconect(Channel channel) {
        //此处可改为原子操作
        synchronized(channel){
            if(channels.indexOf(channel) == -1){
                return ;
            }

            Channel newChannel = bootstrap.connect("0.0.0.0", 9099).channel();
            channels.set(channels.indexOf(channel), newChannel);

            System.out.println(channels.indexOf(channel) + "位置的channel成功进行重连!");
        }
    }

}

本类采用对象组的方式保存连接。因为一个thread + 队列 == 一个单线程线程池 是线程安全的,任务是线性串行执行的

客户端handler

package com.mym.netty.client;

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

public class ClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("client receive msg:"+msg.toString());
    }
}

测试类

package com.mym.netty.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class StartClient {

    public static void main(String[] args) {
        mutilClient();
    }

    public static void mutilClient(){
        MutilClient client = new MutilClient();
        client.init(5);

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            try {
                System.out.println("请输入:");
                String msg = bufferedReader.readLine();
                client.nextChannel().writeAndFlush(msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

测试

测试步骤:连接服务端后,客户端先向服务端发送消息,客户端进行断网,然后开网,然后再想服务端发送消息

客户端输出如下:

请输入:
nihao
client receive msg:this is ServerHandler reply msg happend at !1531894695900this is ServerHandler2 reply msg happend at !1531894695902

此处断网,一大堆错。然后重新开网,再次发送消息
请输入:
hello
-1位置的channel成功进行重连!
client receive msg:this is ServerHandler reply msg happend at !1531894961093
client receive msg:this is ServerHandler2 reply msg happend at !1531894961094

本次实现仍有可优化的地方,欢迎留言给出建议

猜你喜欢

转载自blog.csdn.net/maoyuanming0806/article/details/81102900