更新了附加代码
使用Netty 4.0.12,如果我们尝试在连接websocket后立即发送消息,我们将从HttpObjectEncoder获取IllegalStateException(请参阅底部的异常)。如果我睡了1-2秒,那么一切都很好。
我认为这是因为我们没有正确处理ChannelFuture,但我相信我已经通过使用ChannelFuture上的以下逻辑等待未来完成来确定连接已完成之前我们尝试用它。
不幸的是,这并没有解决它。如果有人知道可能导致这种情况的原因,请告诉我。
提前致谢, 鲍勃
=====================
WEBSOCKET CREATION
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;
}
PIPELINE INIT
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());
}
}
CHANNEL WAIT LOGIC
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]
答案 0 :(得分:0)
看起来正在发生的是这个
1)客户端发送升级请求
2)服务器向客户端发送升级响应,触发本地HANDSHAKE_COMPLETED事件
3)上游服务器处理程序听到事件,开始向客户端发送websocket框架
4)客户端收到升级响应(HTTP 101)
5)客户端在#4到达websocket握手之前收到第一个websocket框架
HttpClientCodec在处理websocket框架时抛出异常,导致websocket握手关闭连接
6)客户端进程升级响应并删除HttpClientCodec (oops,为时已晚)
我也看到4.0.14.Final,但是在管道前面有HttpClientCodec。
**更新**
这是固定的,顺便说一句:https://github.com/netty/netty/issues/2173