Netty4 websocket:如果我们在websocket连接后试图太快发送消息,则从HttpObjectDecoder获取IllegalStateException

Netty4 websocket:如果我们在websocket连接后试图太快发送消息,则从HttpObjectDecoder获取IllegalStateException,websocket,netty,Websocket,Netty,已更新,带有附加代码 使用Netty 4.0.12,如果我们尝试在连接websocket后立即发送消息,我们将从HttpObjectEncoder获得一个非法状态异常(请参见底部的异常)。如果我睡1-2秒,那么一切都很好 我认为这是因为我们没有正确处理ChannelFuture,但我相信我已经修复了这一问题,通过使用ChannelFuture上的以下逻辑等待未来完成,以确保在尝试使用它之前连接已完成 不幸的是,这并没有解决它。如果有人知道这可能是什么原因,请告诉我 提前感谢,, 鲍勃 =====

已更新,带有附加代码

使用Netty 4.0.12,如果我们尝试在连接websocket后立即发送消息,我们将从HttpObjectEncoder获得一个非法状态异常(请参见底部的异常)。如果我睡1-2秒,那么一切都很好

我认为这是因为我们没有正确处理ChannelFuture,但我相信我已经修复了这一问题,通过使用ChannelFuture上的以下逻辑等待未来完成,以确保在尝试使用它之前连接已完成

不幸的是,这并没有解决它。如果有人知道这可能是什么原因,请告诉我

提前感谢,, 鲍勃

=====================

WEBSOCKET创建

public synchronized Channel createWebSocket(String id, NettyClientConnection connection) throws Exception
{
    URI serverUri = connection.getServerUri();
    final ClientHandler clientHandler = new ClientHandler(connection);

    this.getBootstrap().handler(new ChannelPipelineInitializer(serverUri, clientHandler));

    ChannelFuture future = this.getBootstrap().connect(serverUri.getHost(), serverUri.getPort());

    // verify connect has completed successfully
    NettyUtils.waitForChannelCompletion(future, "connecting websocket");

    Channel websocket = future.channel();

    return websocket;
}
管道初始化

public class ChannelPipelineInitializer extends ChannelInitializer<SocketChannel> 
{
    private URI _serverUri = null;
    protected URI getServerUri(){return this._serverUri;}

    private ClientHandler _clientHandler = null;
    protected ClientHandler getClientHandler(){return this._clientHandler;}

    public ChannelPipelineInitializer(URI serverUri, ClientHandler clientHandler)
    {
        this._serverUri = serverUri;
        this._clientHandler = clientHandler;
    }

    @Override
    public void initChannel(SocketChannel channel) throws Exception 
    {
        ChannelPipeline pipeline = channel.pipeline();

        boolean handleCloseFrames = false;
        WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(this.getServerUri(), WebSocketVersion.V13, null, false, null);

        final WebSocketClientProtocolHandler websocketHandler = new WebSocketClientProtocolHandler(handshaker, handleCloseFrames);

        DefaultEventExecutorGroup nettyExecutor = new DefaultEventExecutorGroup(10);

        pipeline.addLast(PipelineConstants.HttpClientCodec, new HttpClientCodec());
        pipeline.addLast(PipelineConstants.HttpAggregator, new HttpObjectAggregator(65536));
        pipeline.addLast(PipelineConstants.WebSocketClientProtocolHandler, websocketHandler);
        pipeline.addLast(PipelineConstants.ThingworxMessageCodec, new ThingworxMessageCodec());

        // use netty executor to free up initial IO thread
        pipeline.addLast(nettyExecutor, this.getClientHandler());
    }
}
异常堆栈
看起来发生的事情是这样的

1) 客户端发送升级请求

2) 服务器向客户端发送升级响应,触发本地握手\u完成事件

3) 上游服务器处理程序听到事件,开始向客户端发送websocket帧

4) 客户端收到升级响应(HTTP 101)

5) 客户端在#4到达websocket握手器之前收到第一个websocket帧

HttpClientCodec在处理websocket帧时在此处引发异常,导致websocket握手器关闭连接

6) 客户端处理升级响应并删除HttpClientCodec(oops,太晚了)

我在4.0.14.Final中也看到了这一点,但是在管道前端使用了HttpClientCodec

**更新**


这是固定的,顺便说一句:

你能给我看一下你握手的全部代码吗?请看更新的代码,谢谢
public static void waitForChannelCompletion(ChannelFuture future, String operationMessage) throws IOCompletionException
{
    future.awaitUninterruptibly();

    // Now we are sure the future is completed.
    if (future.isDone())
    {
        if (future.isCancelled())
        {
            String errorMsg = String.format("IO Operation has been cancelled [operation: %s]", operationMessage);
            throw new IOCompletionException(errorMsg);
        }
        else if (future.isSuccess() == false) 
        {
            String errorMsg = String.format("IO Operation failed [operation: %s]", operationMessage);
            throw new IOCompletionException(errorMsg, future.cause());
        }
    }
    else
    {
        // future should be done, otherwise there's a problem
        String errorMsg = String.format("IO Operation never completed [operation: %s]", operationMessage);
        throw new IOCompletionException(errorMsg);
    }
}
2013-11-21 13:32:16.767-0500 [ERROR] [c.t.t.t.SendTask] [T: pool-2-thread-9] Client_9 Attempt to send message failed. java.lang.IllegalStateException: unexpected message type: UnpooledUnsafeDirectByteBuf
    at io.netty.handler.codec.http.HttpObjectEncoder.encode(HttpObjectEncoder.java:80) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.handler.codec.http.HttpClientCodec$Encoder.encode(HttpClientCodec.java:94) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:89) ~[netty-all-4.0.12.Final.jar:na] Wrapped by: io.netty.handler.codec.EncoderException: java.lang.IllegalStateException: unexpected message type: UnpooledUnsafeDirectByteBuf
    at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:107) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.CombinedChannelDuplexHandler.write(CombinedChannelDuplexHandler.java:193) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:645) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.write(DefaultChannelHandlerContext.java:699) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.write(DefaultChannelHandlerContext.java:638) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:115) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:645) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.write(DefaultChannelHandlerContext.java:699) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.write(DefaultChannelHandlerContext.java:638) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:115) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.handler.codec.MessageToMessageCodec.write(MessageToMessageCodec.java:116) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:645) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext.access$2000(DefaultChannelHandlerContext.java:29) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.DefaultChannelHandlerContext$WriteTask.run(DefaultChannelHandlerContext.java:906) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:354) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:353) ~[netty-all-4.0.12.Final.jar:na]
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101) ~[netty-all-4.0.12.Final.jar:na]
    at java.lang.Thread.run(Thread.java:744) [na:1.7.0_45]