ScheduledFuture只运行14次

时间:2016-06-17 09:54:20

标签: java netty

我有一个非常奇怪的错误(或者我的错误)。我在Netty上有非常简单的HTTP客户端和服务器。

客户端应每隔X秒连接到服务器,并发送GET请求并附加一些Cookie。那就是全部。

客户端执行此操作14次,然后停止执行。我试图调试问题,发现它在

后停止
ChannelFuture channelFuture = clientNio.getBootstrap().connect().sync();
System.out.println("Connected!");

它停滞不前,没有任何反应。

客户的代码段:

public class Test{

public static int count = 0;


public static void main(String[] args) throws Exception {

    /** Start NIO client:
     * 1. Create new session to the server
     * 2. Create new client NIO and pass the session in it
     * 3. Start client NIO
     * */
    NetworkSession session = new NetworkSession(new InetSocketAddress("127.0.0.1",8080));
    ClientNio clientNio = new ClientNio(session);
    clientNio.start();



    // This is URL for server (should take from session)
    String URL = System.getProperty("url", "http://127.0.0.1:8080/");
    URI uri = new URI(URL);
    String scheme = uri.getScheme() == null? "http" : uri.getScheme();
    String host = uri.getHost() == null? "127.0.0.1" : uri.getHost();
    int port = uri.getPort();
    String rawPath = uri.getRawPath();

    /** Because we use Netty it is logical to use it's EvenLoopGroup to schedule connection with the server each X seconds*/
    ScheduledFuture<?> future = clientNio.getGroup().scheduleAtFixedRate(
            new Runnable() {
                @Override
                public void run() {
                    try {
                        //  Make the connection attempt
                        ChannelFuture channelFuture = clientNio.getBootstrap().connect().sync();
                        System.out.println("Connected!");
                        Channel channel = channelFuture.channel();
                        System.out.println("Get channel " + channel);

                        // After we get connection we update our session state
                        session.setSessionChannel(channel);
                        session.setInternalAddress((InetSocketAddress) channel.localAddress());
                        // And get session metadata to be send to the server
                        String sessionMetaDataEncoded = Base64.encodeToString(session.getMetadata());

                        // Prepare the HTTP request
                        HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, rawPath);
                        //request.headers().set(request.headers().set(HttpHeaderNames.HOST, host));
                        request.headers().set(HttpHeaderNames.HOST, host);
                        request.headers().set(HttpHeaderNames.CONNECTION,  HttpHeaderValues.CLOSE);
                        request.headers().set("Cookie", ClientCookieEncoder.STRICT.encode("sesionID",sessionMetaDataEncoded));


                        // Send the HTTP request.
                        channel.writeAndFlush(request);

                        // Wait for the server to close the connection.
                        channel.closeFuture().sync();
                        System.out.println("closed");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(count);
                    count++;
                }
            }, 0, 1, TimeUnit.SECONDS);
}

}

客户NIO:

public class ClientNio {

private final InetSocketAddress serverAddress;
private final NetworkSession session;
private Bootstrap bootstrap;
private EventLoopGroup group;


//GETTERS
public Bootstrap getBootstrap() {
    return bootstrap;
}
public EventLoopGroup getGroup() {return group;}

public ClientNio(NetworkSession session) {
    this.session = session;
    this.serverAddress = this.session.getServerAddress();
}


public void start() {
    group = new NioEventLoopGroup();
    bootstrap = new Bootstrap();
    bootstrap.group(group)
            .channel(NioSocketChannel.class)
            .remoteAddress(serverAddress)
            .handler(new HTTPClientPipelineInitializer(session));
}

public void stop() {
    try {
        group.shutdownGracefully().sync();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

客户端管道初始化程序

public class HTTPClientPipelineInitializer extends ChannelInitializer<SocketChannel> {

private final NetworkSession session;

public HTTPClientPipelineInitializer(NetworkSession session) {
    this.session = session;
}

@Override
protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();

    pipeline.addLast("codec", new HttpClientCodec());
    /** Adds HttpObjectAggregator with a max message size of 512 KB to the pipeline */
    pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));
}

}

P.S。我发现它在ScheduledFutureTask类中被停止,它在第15步是例外。

io.netty.util.concurrent.BlockingOperationException:DefaultChannelPromise@1919f0ff(incomplete)

如何处理?

1 个答案:

答案 0 :(得分:1)

经过一些调试后,我抓住了这个问题的想法。因为我们在同步期间使用EvenLoop,我可能会被阻止,这将导致

当用户在事件循环线程中执行阻止操作时引发的IllegalStateException。如果在事件循环线程中执行阻塞操作,阻塞操作很可能会进入死锁状态,从而抛出此异常。

所以在我的情况下,我去了简单的ScheduledFuture future = scheduler.scheduleAtFixedRate,一切正常。