List of usage examples for io.netty.handler.codec.http.websocketx CloseWebSocketFrame CloseWebSocketFrame
public CloseWebSocketFrame(boolean finalFragment, int rsv)
From source file:catacumba.websocket.internal.DefaultWebSocket.java
License:Apache License
@Override public void close(int statusCode, String reason) { open.set(false);/*from w ww .j a va2s . c o m*/ channel.writeAndFlush(new CloseWebSocketFrame(statusCode, reason)); channel.close().addListener(future -> onClose.run()); }
From source file:com.vmware.dcp.common.http.netty.NettyWebSocketRequestHandler.java
License:Open Source License
/** * Processes incoming web socket frame. {@link PingWebSocketFrame} and {@link CloseWebSocketFrame} frames are * processed in a usual way. {@link io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame} frames are not * supported. {@link TextWebSocketFrame} frames are processed as described below. * <p/>/*from ww w . j a va 2 s . c o m*/ * Whenever invalid frame is encountered - the underlying connection is closed. * <p/> * <h3>Incoming frame format</h3> * Incoming frame format is the same for all frames: * <pre> * REQUEST_ID * METHOD URI * {jsonPayload} (Optional and may be multiline) * </pre> * REQUEST_ID is an arbitrary string generated on client which is used to correlate server response with * original client request. This string is included into response frames (described below). REQUEST_ID should * be unique within the same web socket connection. * <p/> * METHOD is one of [POST, DELETE, REPLY] and URI is service path, such as {@code /core/ws-service}. * <p/> * Web socket connection is not a proxy, so arbitrary methods and request URIs are not supported. * <p/> * Line breaks are always CRLF similar to HTTP * (<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2">RFC 2616</a>). * <p/> * <h3>Outgoing frame format</h3> * {@link io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame} frames are never sent to client. * Text frames have the following format: * <pre> * (RESULT_CODE REQUEST_ID (optional line))|(HTTP_METHOD SERVICE_URI) * {jsonPayload} * </pre> * RESULT_CODE is one of 200, 404, 500 with similar meanings to corresponding HTTP codes (OK, NOT_FOUND, ISE). * <p/> * REQUEST_ID is the same string which was passed by client in initial request. * <p/> * SERVICE_URI - a URI assigned to the client-side service. * <p/> * Json payload is either server response on request (in case when first line is RESULT_CODE REQUEST_ID) or * {@link com.vmware.dcp.common.Operation.SerializedOperation} in case when this frame is an operation to be * complete by a client service and first line is HTTP_METHOD SERVICE_URI. Method name corresponds to * {@link com.vmware.dcp.common.Operation.SerializedOperation#action} specified in the serialized operation. * <h3>Possible incoming request</h3> * All below requests should conform spec above. REQUEST_ID is omitted everywhere below to simplify the doc. * <ul> * <li>POST /core/ws-service with no body - requests a new service to be created. Response body is * {"uri": "http://some-ip-addr/core/ws-service/some-uuid"} where uri value is assigned temporary link to the * service. <b>ToDo: make node IP addresses invisible to client</b></li> * <li>DELETE /core/ws-service/some-uuid with no body - removes previously created web socket service. * Service should be defined in the same web socket connection.</li> * <li>POST /someservicepath/subscriptions with standard subscription body - subscribes the specified * service to the specified target service. Observer must be a web socket-based serviced created within * current connection. Subscription is removed automatically whenever web socket connection is broken.</li> * <li>DELETE /someservicepath/subscriptions with standard subscription body - removes previously created * subscription. Subscription should be made via request specified above within the same connection</li> * <li>REPLY /core/ws-service with serialized operation as body - should be issued in response for an * incoming request. No response from the server is assumed and REQUEST_ID field is ignored. * </li> * </ul> * * @param ctx Netty channel context handler * @param frame Incoming websocket frame */ private void processWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { if (frame instanceof CloseWebSocketFrame) { this.handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain())); return; } if (!(frame instanceof TextWebSocketFrame)) { this.handshaker.close(ctx.channel(), new CloseWebSocketFrame(1003, String.format("%s frame types not supported", frame.getClass().getName()))); return; } TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; String text = textFrame.text(); int requestIdSep = text.indexOf(Operation.CR_LF); if (requestIdSep < 0) { this.handshaker.close(ctx.channel(), new CloseWebSocketFrame(1003, "Malformed frame")); return; } String requestId = text.substring(0, requestIdSep); int requestLineSep = text.indexOf(Operation.CR_LF, requestIdSep + Operation.CR_LF.length()); String body; if (requestLineSep < 0) { requestLineSep = text.length(); body = ""; } else { body = text.substring(requestLineSep + Operation.CR_LF.length()); } String requestLine = text.substring(requestIdSep + Operation.CR_LF.length(), requestLineSep); int methodSep = requestLine.indexOf(" "); if (methodSep < 0) { this.handshaker.close(ctx.channel(), new CloseWebSocketFrame(1003, "Malformed frame")); return; } String method = requestLine.substring(0, methodSep); String path = requestLine.substring(methodSep + 1); try { if (method.equals("DELETE")) { if (path.startsWith(this.servicePrefix)) { // Shutdown service permanently and delete all known service subscriptions URI serviceToDelete = UriUtils.buildPublicUri(this.host, path); WebSocketService removed = this.webSocketServices.remove(serviceToDelete); if (removed != null) { deleteServiceSubscriptions(removed); this.host.stopService(removed); ctx.writeAndFlush(new TextWebSocketFrame("200 " + requestId)); } else { ctx.writeAndFlush(new TextWebSocketFrame("404 " + requestId)); } return; } if (path.endsWith(ServiceHost.SERVICE_URI_SUFFIX_SUBSCRIPTIONS)) { // Delete a single subscription ServiceSubscriptionState.ServiceSubscriber state = Utils.fromJson(body, ServiceSubscriptionState.ServiceSubscriber.class); WebSocketService service = this.webSocketServices.get(state.reference); this.host.sendRequest(Operation.createDelete(service, path).setBody(body) .setReferer(service.getUri()).setCompletion((completedOp, failure) -> { ctx.writeAndFlush( new TextWebSocketFrame(completedOp.getStatusCode() + " " + requestId)); Utils.atomicGetOrCreate(this.serviceSubscriptions, service.getUri(), ConcurrentSkipListSet::new).remove(path); })); return; } ctx.writeAndFlush(new TextWebSocketFrame( Integer.toString(Operation.STATUS_CODE_NOT_FOUND) + " " + requestId)); return; } if (method.equals(Action.POST.toString())) { if (path.equals(this.servicePrefix)) { // Create a new ephemeral service URI wsServiceUri = buildWsServiceUri(java.util.UUID.randomUUID().toString()); CreateServiceResponse response = new CreateServiceResponse(); response.uri = wsServiceUri.toString(); WebSocketService webSocketService = new WebSocketService(ctx, wsServiceUri); this.host.startService(Operation.createPost(wsServiceUri).setCompletion((o, t) -> { if (t != null) { ctx.writeAndFlush(new TextWebSocketFrame( Integer.toString(Operation.STATUS_CODE_SERVER_FAILURE_THRESHOLD) + " " + requestId + Operation.CR_LF + Utils.toJson(t))); } else { ctx.writeAndFlush( new TextWebSocketFrame(Integer.toString(Operation.STATUS_CODE_ACCEPTED) + " " + requestId + Operation.CR_LF + Utils.toJson(response))); } }), webSocketService); this.webSocketServices.put(wsServiceUri, webSocketService); return; } if (path.endsWith(ServiceHost.SERVICE_URI_SUFFIX_SUBSCRIPTIONS)) { // Subscribe for service updates with auto-unsubscribe ServiceSubscriptionState.ServiceSubscriber state = Utils.fromJson(body, ServiceSubscriptionState.ServiceSubscriber.class); WebSocketService service = this.webSocketServices.get(state.reference); this.host.sendRequest(Operation.createPost(service, path).setBody(body) .setReferer(service.getUri()).setCompletion((completedOp, failure) -> { ctx.writeAndFlush( new TextWebSocketFrame(completedOp.getStatusCode() + " " + requestId)); if (completedOp.getStatusCode() >= 200 && completedOp.getStatusCode() < 300) { Utils.atomicGetOrCreate(this.serviceSubscriptions, service.getUri(), ConcurrentSkipListSet::new).add(path); } })); return; } } if (method.equals("REPLY")) { if (path.startsWith(this.servicePrefix) && path.length() > this.servicePrefix.length()) { // Forward ephemeral service response to the caller String serviceId = path.substring(this.servicePrefix.length() + 1); URI serviceUri = buildWsServiceUri(serviceId); WebSocketService service = this.webSocketServices.get(serviceUri); if (service != null) { service.handleWebSocketMessage(body); } return; } } ctx.writeAndFlush(new TextWebSocketFrame("404 " + requestId)); this.host.log(Level.FINE, "Unsupported websocket request: %s %s %s", method, path, body); } catch (Exception e) { ctx.writeAndFlush("500 " + requestId); } }
From source file:com.vmware.xenon.common.http.netty.NettyWebSocketRequestHandler.java
License:Open Source License
@Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { FullHttpRequest nettyRequest = (FullHttpRequest) msg; this.handshakeAccepted = true; performWebsocketHandshake(ctx, nettyRequest); return;// w w w. j a v a 2s . co m } if (msg instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) msg; if (frame instanceof CloseWebSocketFrame) { this.handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain())); return; } if (!(frame instanceof TextWebSocketFrame)) { this.handshaker.close(ctx.channel(), new CloseWebSocketFrame(1003, String.format("%s frame types not supported", frame.getClass().getName()))); return; } String frameText = ((TextWebSocketFrame) frame).text(); this.host.run(() -> { if (this.authToken != null) { Operation dummyOp = new Operation(); dummyOp.addRequestHeader(Operation.REQUEST_AUTH_TOKEN_HEADER, this.authToken); dummyOp.setUri(UriUtils.buildUri(this.host, ServiceUriPaths.CORE_WEB_SOCKET_ENDPOINT)); OperationContext.setAuthorizationContext(this.host, dummyOp); } processWebSocketFrame(ctx, frameText); }); return; } }
From source file:com.vmware.xenon.common.http.netty.NettyWebSocketRequestHandler.java
License:Open Source License
/** * Processes incoming web socket frame. {@link PingWebSocketFrame} and {@link CloseWebSocketFrame} frames are * processed in a usual way. {@link io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame} frames are not * supported. {@link TextWebSocketFrame} frames are processed as described below. <p/> Whenever invalid frame is * encountered - the underlying connection is closed. <p/> <h3>Incoming frame format</h3> Incoming frame format is * the same for all frames:// ww w . ja va2s .c om * <pre> * REQUEST_ID * METHOD URI * {jsonPayload} (Optional and may be multiline) * </pre> * REQUEST_ID is an arbitrary string generated on client which is used to correlate server response with * original client request. This string is included into response frames (described below). REQUEST_ID should * be unique within the same web socket connection. * <p/> * METHOD is one of [POST, DELETE, REPLY] and URI is service path, such as {@code /core/ws-service}. * <p/> * Web socket connection is not a proxy, so arbitrary methods and request URIs are not supported. * <p/> * Line breaks are always CRLF similar to HTTP * (<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2">RFC 2616</a>). * <p/> * <h3>Outgoing frame format</h3> * {@link io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame} frames are never sent to client. * Text frames have the following format: * <pre> * (RESULT_CODE REQUEST_ID (optional line))|(HTTP_METHOD SERVICE_URI) * {jsonPayload} * </pre> * RESULT_CODE is one of 200, 404, 500 with similar meanings to corresponding HTTP codes (OK, NOT_FOUND, ISE). * <p/> * REQUEST_ID is the same string which was passed by client in initial request. * <p/> * SERVICE_URI - a URI assigned to the client-side service. * <p/> * Json payload is either server response on request (in case when first line is RESULT_CODE REQUEST_ID) or * {@link com.vmware.xenon.common.Operation.SerializedOperation} in case when this frame is an operation to be * complete by a client service and first line is HTTP_METHOD SERVICE_URI. Method name corresponds to * {@link com.vmware.xenon.common.Operation.SerializedOperation#action} specified in the serialized operation. * <h3>Possible incoming request</h3> * All below requests should conform spec above. REQUEST_ID is omitted everywhere below to simplify the doc. * <ul> * <li>POST /core/ws-service with no body - requests a new service to be created. Response body is * {"uri": "http://some-ip-addr/core/ws-service/some-uuid"} where uri value is assigned temporary link to the * service. <b>ToDo: make node IP addresses invisible to client</b></li> * <li>DELETE /core/ws-service/some-uuid with no body - removes previously created web socket service. * Service should be defined in the same web socket connection.</li> * <li>POST /someservicepath/subscriptions with standard subscription body - subscribes the specified * service to the specified target service. Observer must be a web socket-based serviced created within * current connection. Subscription is removed automatically whenever web socket connection is broken.</li> * <li>DELETE /someservicepath/subscriptions with standard subscription body - removes previously created * subscription. Subscription should be made via request specified above within the same connection</li> * <li>REPLY /core/ws-service with serialized operation as body - should be issued in response for an * incoming request. No response from the server is assumed and REQUEST_ID field is ignored. * </li> * </ul> * * @param ctx Netty channel context handler * @param text Incoming websocket frame text */ private void processWebSocketFrame(ChannelHandlerContext ctx, String text) { int requestIdSep = text.indexOf(Operation.CR_LF); if (requestIdSep < 0) { this.handshaker.close(ctx.channel(), new CloseWebSocketFrame(1003, "Malformed frame")); return; } String requestId = text.substring(0, requestIdSep); int requestLineSep = text.indexOf(Operation.CR_LF, requestIdSep + Operation.CR_LF.length()); String body; if (requestLineSep < 0) { requestLineSep = text.length(); body = ""; } else { body = text.substring(requestLineSep + Operation.CR_LF.length()); } String requestLine = text.substring(requestIdSep + Operation.CR_LF.length(), requestLineSep); int methodSep = requestLine.indexOf(" "); if (methodSep < 0) { this.handshaker.close(ctx.channel(), new CloseWebSocketFrame(1003, "Malformed frame")); return; } String method = requestLine.substring(0, methodSep); String path = requestLine.substring(methodSep + 1); try { if (method.equals("DELETE")) { if (path.startsWith(this.servicePrefix)) { // Shutdown service permanently and delete all known service subscriptions URI serviceToDelete = UriUtils.buildPublicUri(this.host, path); WebSocketService removed = this.webSocketServices.remove(serviceToDelete); if (removed != null) { deleteServiceSubscriptions(removed); this.host.stopService(removed); ctx.writeAndFlush(new TextWebSocketFrame("200 " + requestId)); } else { ctx.writeAndFlush(new TextWebSocketFrame("404 " + requestId)); } return; } if (path.endsWith(ServiceHost.SERVICE_URI_SUFFIX_SUBSCRIPTIONS)) { // Delete a single subscription ServiceSubscriptionState.ServiceSubscriber state = Utils.fromJson(body, ServiceSubscriptionState.ServiceSubscriber.class); WebSocketService service = this.webSocketServices.get(state.reference); this.host.sendRequest(Operation.createDelete(service, path).setBody(body) .setReferer(service.getUri()).setCompletion((completedOp, failure) -> { ctx.writeAndFlush( new TextWebSocketFrame(completedOp.getStatusCode() + " " + requestId)); Utils.atomicGetOrCreate(this.serviceSubscriptions, service.getUri(), ConcurrentSkipListSet::new).remove(path); })); return; } ctx.writeAndFlush(new TextWebSocketFrame( Integer.toString(Operation.STATUS_CODE_NOT_FOUND) + " " + requestId)); return; } if (method.equals(Action.POST.toString())) { if (path.equals(this.servicePrefix)) { // Create a new ephemeral service URI wsServiceUri = buildWsServiceUri(java.util.UUID.randomUUID().toString()); CreateServiceResponse response = new CreateServiceResponse(); response.uri = wsServiceUri.toString(); WebSocketService webSocketService = new WebSocketService(ctx, wsServiceUri); this.host.startService(Operation.createPost(wsServiceUri).setCompletion((o, t) -> { if (t != null) { ctx.writeAndFlush(new TextWebSocketFrame( Integer.toString(Operation.STATUS_CODE_SERVER_FAILURE_THRESHOLD) + " " + requestId + Operation.CR_LF + Utils.toJson(t))); } else { ctx.writeAndFlush( new TextWebSocketFrame(Integer.toString(Operation.STATUS_CODE_ACCEPTED) + " " + requestId + Operation.CR_LF + Utils.toJson(response))); } }), webSocketService); this.webSocketServices.put(wsServiceUri, webSocketService); return; } if (path.endsWith(ServiceHost.SERVICE_URI_SUFFIX_SUBSCRIPTIONS)) { // Subscribe for service updates with auto-unsubscribe ServiceSubscriptionState.ServiceSubscriber state = Utils.fromJson(body, ServiceSubscriptionState.ServiceSubscriber.class); WebSocketService service = this.webSocketServices.get(state.reference); this.host.sendRequest(Operation.createPost(service, path).setBody(body) .setReferer(service.getUri()).setCompletion((completedOp, failure) -> { ctx.writeAndFlush( new TextWebSocketFrame(completedOp.getStatusCode() + " " + requestId)); if (completedOp.getStatusCode() >= 200 && completedOp.getStatusCode() < 300) { Utils.atomicGetOrCreate(this.serviceSubscriptions, service.getUri(), ConcurrentSkipListSet::new).add(path); } })); return; } } if (method.equals("REPLY")) { if (path.startsWith(this.servicePrefix) && path.length() > this.servicePrefix.length()) { // Forward ephemeral service response to the caller String serviceId = path.substring(this.servicePrefix.length() + 1); URI serviceUri = buildWsServiceUri(serviceId); WebSocketService service = this.webSocketServices.get(serviceUri); if (service != null) { service.handleWebSocketMessage(body); } return; } } ctx.writeAndFlush(new TextWebSocketFrame("404 " + requestId)); this.host.log(Level.FINE, "Unsupported websocket request: %s %s %s", method, path, body); } catch (Exception e) { ctx.writeAndFlush("500 " + requestId); } }
From source file:de.saxsys.synchronizefx.netty.websockets.NettyWebsocketClient.java
License:Open Source License
@Override public void disconnect() { eventLoopGroup.schedule(new Runnable() { @Override/*from ww w . j ava 2s . co m*/ public void run() { // Forcefully disconnect the channel if the server failed to close it and shut down the event loop. NettyWebsocketClient.super.disconnect(); } }, GRACEFULL_SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS); channel.writeAndFlush(new CloseWebSocketFrame(1001, "The connection was terminated by the user.")); }
From source file:discord4j.gateway.DiscordWebSocketHandler.java
License:Open Source License
public Mono<Void> handle(WebsocketInbound in, WebsocketOutbound out) { AtomicReference<CloseStatus> reason = new AtomicReference<>(); in.withConnection(connection -> connection.addHandlerLast(HANDLER, new CloseHandlerAdapter(reason, log))); Mono<Void> completionFuture = completionNotifier.log(shardLogger(".zip"), Level.FINEST, false); Mono<CloseWebSocketFrame> closeFuture = closeTrigger .map(status -> new CloseWebSocketFrame(status.getCode(), status.getReason())); Mono<Void> outboundEvents = out.options(NettyPipeline.SendOptions::flushOnEach) .sendObject(Flux.merge(closeFuture, outbound.map(TextWebSocketFrame::new))).then() .doOnTerminate(() -> {/*from ww w . j ava 2 s. co m*/ shardLogger(".outbound").info("Sender completed on shard {}", shardIndex); if (!closeTrigger.isTerminated()) { CloseStatus closeStatus = reason.get(); if (closeStatus != null) { shardLogger(".outbound").info("Forwarding close reason: {}", closeStatus); error(new CloseException(closeStatus)); } else { error(new RuntimeException("Sender completed")); } } }).log(shardLogger(".zip.out"), Level.FINEST, false); Mono<Void> inboundEvents = in.aggregateFrames().receiveFrames().map(WebSocketFrame::content) .compose(decompressor::completeMessages).doOnNext(inbound::next).doOnError(this::error) .then(Mono.<Void>defer(() -> { shardLogger(".inbound").info("Receiver completed on shard {}", shardIndex); CloseStatus closeStatus = reason.get(); if (closeStatus != null && !closeTrigger.isTerminated()) { shardLogger(".inbound").info("Forwarding close reason: {}", closeStatus); return Mono.error(new CloseException(closeStatus)); } return Mono.empty(); })).log(shardLogger(".zip.in"), Level.FINEST, false); return Mono.zip(completionFuture, outboundEvents, inboundEvents) .doOnError(t -> log.debug("WebSocket session threw an error: {}", t.toString())).then(); }
From source file:io.advantageous.conekt.http.impl.ClientConnection.java
License:Open Source License
@Override public synchronized void close() { if (handshaker == null) { super.close(); } else {/* w w w . j a v a 2 s .c o m*/ // make sure everything is flushed out on close endReadAndFlush(); // close the websocket connection by sending a close frame. handshaker.close(channel, new CloseWebSocketFrame(1000, null)); } }
From source file:io.advantageous.conekt.http.impl.ServerConnection.java
License:Open Source License
@Override public void close() { if (handshaker == null) { super.close(); } else {/*from ww w . ja va 2 s .c o m*/ endReadAndFlush(); handshaker.close(channel, new CloseWebSocketFrame(1000, null)); } }
From source file:io.reactivex.netty.protocol.http.websocket.WebSocketClientServerTest.java
License:Apache License
@Test public void testConnectionClose() throws Exception { TestSequenceExecutor executor = new TestSequenceExecutor() .withClientFrames(new CloseWebSocketFrame(1000, "close")).withExpectedOnServer(1) .withServerFrames(new CloseWebSocketFrame(1001, "close requested")).withExpectedOnClient(1) .execute();//from w ww . j a v a 2 s .c om assertTrue("Expected close on server", executor.getReceivedClientFrames().get(0) instanceof CloseWebSocketFrame); assertTrue("Expected close on server", executor.getReceivedServerFrames().get(0) instanceof CloseWebSocketFrame); }
From source file:io.undertow.websockets.jsr.test.JsrWebSocketServer07Test.java
License:Open Source License
@org.junit.Test public void testCloseFrame() throws Exception { final int code = 1000; final String reasonText = "TEST"; final AtomicReference<CloseReason> reason = new AtomicReference<>(); ByteBuffer payload = ByteBuffer.allocate(reasonText.length() + 2); payload.putShort((short) code); payload.put(reasonText.getBytes("UTF-8")); payload.flip();/* w w w . j av a 2 s .c o m*/ final AtomicBoolean connected = new AtomicBoolean(false); final FutureResult latch = new FutureResult(); final CountDownLatch clientLatch = new CountDownLatch(1); final AtomicInteger closeCount = new AtomicInteger(); class TestEndPoint extends Endpoint { @Override public void onOpen(final Session session, EndpointConfig config) { connected.set(true); } @Override public void onClose(Session session, CloseReason closeReason) { closeCount.incrementAndGet(); reason.set(closeReason); clientLatch.countDown(); } } ServerWebSocketContainer builder = new ServerWebSocketContainer(TestClassIntrospector.INSTANCE, DefaultServer.getWorker(), new ByteBufferSlicePool(100, 100), new CompositeThreadSetupAction(Collections.EMPTY_LIST), false, false); builder.addEndpoint(ServerEndpointConfig.Builder.create(TestEndPoint.class, "/") .configurator(new InstanceConfigurator(new TestEndPoint())).build()); deployServlet(builder); WebSocketTestClient client = new WebSocketTestClient(getVersion(), new URI("ws://" + DefaultServer.getHostAddress("default") + ":" + DefaultServer.getHostPort("default") + "/")); client.connect(); client.send(new CloseWebSocketFrame(code, reasonText), new FrameChecker(CloseWebSocketFrame.class, payload.array(), latch)); latch.getIoFuture().get(); clientLatch.await(); Assert.assertEquals(code, reason.get().getCloseCode().getCode()); Assert.assertEquals(reasonText, reason.get().getReasonPhrase()); Assert.assertEquals(1, closeCount.get()); client.destroy(); }