添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
精彩文章免费看

netty 客户端创建多个连接

netty 客户端需要创建多个连接去连接多个服务端,因为服务方是请求模式,必须我们这边主动发起连接

那是不是我每一个连接都要实例化一个 EventLoopGroup,我觉的不是,EventLoopGroup 是线程池,假设你要连接 10000 个设备,每个连接一个线程都会直接崩掉(10000 个线程要耗费多少资源啊),别说每个连接一个 EventLoopGroup 了。

再说服务端我们有没有每一个连接都创建一个线程呢,没有。服务端一般都是两个线程池, 一个 boss 负责接收连接请求, 一个 work 负责 IO 读写。所以客户端多个连接也是要共用一个 EventLoopGroup 的。客户端不需要接收连接,所以只需要一个EventLoopGroup 就行了。多路复用器 selector 的使用,使得一个线程就可以轮询成千上万个连接。

参考我写的demo理解一下

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.concurrent.TimeUnit;
public class NettyClient {
    private Bootstrap b = new Bootstrap();
    private EventLoopGroup group;
    public NettyClient() {
        group = new NioEventLoopGroup();
        b.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
    public void connect(String host, int port) {
        System.out.println("11111111111 connect " + host + " " + Thread.currentThread());
        b.connect(host, port).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                 * 这里就不是主线程了,这里是 netty 线程中执行
                if (future.isSuccess()) {
                    System.out.println("2222222222222 connect success " + host + " " + Thread.currentThread());
                } else {
                    System.out.println("333333333333333 connect failed " + host + " " + Thread.currentThread());
                    // 连接不成功,5秒后重新连接
                    future.channel().eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("4444444444444  reconnect " + host + " " + Thread.currentThread());
                            connect(host, port);
                    }, 5, TimeUnit.SECONDS);
    public void stop() {
        if (group != null) {
            group.shutdownGracefully();
            group = null;
    public static void main(String[] args) {
        String[] ips = new String[]{
                "192.168.1.100",
                "192.168.1.101",
                "192.168.1.102",
        NettyClient nettyClient = new NettyClient();
        for (int i = 0; i < ips.length; i++) {
            nettyClient.connect(ips[i], 4001);
        // 这里主线程提前退出了,但JVM进程没有退出
        System.out.println("main thread finish");

这里其实演示了首次连接连不上一直重连的场景,还有一种断线重连也很简单, 断线 channeInactivie 时再从新 connect 就行了。

注意 connect(host, port) 后面没有调用 sync 进行同步阻塞,而是注册异步监听器。如果调用 sync 会一直阻塞调用线程直到连接成功或失败。

测试中发现了一个问题, 我的主线程提前结束了,但进程并没有结束,只有把 netty 的线程池 shutdown 以后进程才会退出,这是为什么呢????

因为 JVM 只有在所有非 Daemon 线程都结束时才会退出,由于 netty 的线程还在,所以主线程结束后 JVM 并未退出。

最后编辑于:2020-06-28 23:39