简体   繁体   English

净额和定期执行人服务

[英]Netty and Scheduled Executor Service

I'm trying to create a TCP server that read data periodically from a database (Redis) and send it to the appropriate client. 我正在尝试创建一个TCP服务器,该服务器定期从数据库(Redis)读取数据并将其发送到适当的客户端。

However, since I'm pretty new to Netty, I don't know how could I schedule this. 但是,由于我是Netty的新手,所以我不知道该如何安排。 I do know that I need to use a Scheduled Executor Service like this: 我知道我需要像这样使用Scheduled Executor服务:

ScheduledExecutorService e = Executors.newSingleThreadScheduledExecutor();
e.scheduleAtFixedRate(() -> {
    System.out.println("Calling...");
    // Do something
}, 1, 1, TimeUnit.SECONDS);

However, when I tried to put that in the server code, It's only calling the method once. 但是,当我尝试将其放入服务器代码中时,它仅调用一次该方法。 I've tried to put that in different place but still can't seem to get it right. 我尝试将其放在其他位置,但似乎仍无法正确处理。 What should I do? 我该怎么办?

Here's the code of the server: 这是服务器的代码:

package com.example.test.app;

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 java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Server {

    public static void main(String[] args) throws Exception
    {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        final ServerHandler handler = new ServerHandler();

        try {

            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup);
            b.channel(NioServerSocketChannel.class);
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception
                {
                    ch.pipeline().addLast(handler);
                }

            });
            b.option(ChannelOption.SO_BACKLOG, 128);
            b.childOption(ChannelOption.SO_KEEPALIVE, true);

            ScheduledExecutorService e = Executors.newSingleThreadScheduledExecutor();
            e.scheduleAtFixedRate(() -> {
                System.out.println("Calling...");
                handler.saySomething();
            }, 1, 1, TimeUnit.SECONDS);

            ChannelFuture f = b.bind(1337).sync();
            f.channel().closeFuture().sync();

        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

}

And here's the server handler: 这是服务器处理程序:

package com.example.test.app;

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

public class ServerHandler extends ChannelInboundHandlerAdapter {

    private ChannelHandlerContext ctx;

    @Override
    public void channelActive(ChannelHandlerContext ctx)
    {
        this.ctx = ctx;
        System.out.println("Someone's connedted!");
    }

    public void saySomething()
    {
        final ChannelFuture f = ctx.writeAndFlush("Sup!");
        f.addListener((ChannelFutureListener) (ChannelFuture future) -> {
            System.out.println("Something has been said!");
        });
    }

}

The method saySomething() generates NullPointerException for calling final ChannelFuture f = ctx.writeAndFlush("Sup!"); saySomething()方法生成NullPointerException以调用final ChannelFuture f = ctx.writeAndFlush("Sup!"); while ctx is null. ctx为null。 EventExecutorGroup.scheduleAtFixedRate javadoc description says that "If any execution of the task encounters an exception, subsequent executions are suppressed". EventExecutorGroup.scheduleAtFixedRate javadoc描述说:“如果任务的任何执行遇到异常,则将抑制后续执行”。 So this is why you get is called only once... 所以这就是为什么您只被调用一次的原因...

Also, seems like Netty allows you to re-use a handler instance for different pipeline instances only if you annotate this handler's class as @Sharable. 此外,似乎Netty仅允许将处理程序的类注释为@Sharable时才允许您将处理程序实例用于不同的管道实例。 Otherwise, it will throw exception. 否则,它将引发异常。 If your handler is stateless (which is not your case, as yours has the ctx member) then you should annotate it as @Sharable and re-use it to all created pipelines. 如果您的处理程序是无状态的(不是这种情况,因为您有ctx成员),则应将其注释为@Sharable并将其重新用于所有创建的管道。 If it is stateful, create a new instance for every new pipeline (new client connection). 如果它是有状态的,则为每个新管道(新客户端连接)创建一个新实例。

Finally, to schedule your task for each connected client you can use the executor which can be referenced by the ctx of the connected client's channel (by default, as in your case, the channel's EventLoop) on your channelActive() implementation. 最后,要为每个连接的客户端安排任务,可以使用执行程序,该执行程序可以由channelActive()实现上的连接的客户端通道的ctx引用(默认情况下,如您的情况,该通道的EventLoop)。 This executor implements ScheduledExecutorService , so you have also scheduleAtFixedRate . 该执行程序实现ScheduledExecutorService ,因此您还具有scheduleAtFixedRate Take a look at my version of your code and see if it suits you. 查看我的代码版本,看看它是否适合您。

Server: 服务器:

package com.example.test.app;

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 java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Server {

    public static void main(String[] args) throws Exception
    {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup);
            b.channel(NioServerSocketChannel.class);
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception
                {
                    ch.pipeline().addLast(new ServerHandler());
                }

            });
            b.option(ChannelOption.SO_BACKLOG, 128);
            b.childOption(ChannelOption.SO_KEEPALIVE, true);

//            ScheduledExecutorService e = Executors.newSingleThreadScheduledExecutor();
//            e.scheduleAtFixedRate(() -> {
//                System.out.println("Calling...");
//                handler.saySomething();
//            }, 1, 1, TimeUnit.SECONDS);

            ChannelFuture f = b.bind(1337).sync();
            f.channel().closeFuture().sync();

        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

}

ServerHandler: ServerHandler:

package com.example.test.app;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.ScheduledFuture;

import java.util.concurrent.TimeUnit;

public class ServerHandler extends ChannelInboundHandlerAdapter {

    private ScheduledFuture sf;

    @Override
    public void channelActive(ChannelHandlerContext ctx)
    {
        System.out.println("Someone's connedted! "+ctx.channel());
        sf = ctx.executor().scheduleAtFixedRate(() -> {
            System.out.println("Calling...");
            saySomething(ctx);
        }, 1, 1, TimeUnit.SECONDS);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println("Someone's disconnected! "+ctx.channel());
        sf.cancel(false);
    }

    private void saySomething(ChannelHandlerContext ctx)
    {
            final ChannelFuture f = ctx.writeAndFlush("Sup!");
            f.addListener((ChannelFutureListener) (ChannelFuture future) -> {
                System.out.println("Something has been said!");
            });
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM