#java #websocket #jetty #jsr356
#java #websocket #причал #jsr356
Вопрос:
Я создал клиент-серверное приложение, используя javax websockets.Хотя в JSR 356 нет методов для остановки контейнера websocket, мне удалось остановить контейнер после приведения к jetty Lifecyle.После остановки контейнера я написал
system.exit(1);
Но возвращаемый код всегда равен нулю из клиентской программы.
код: @ClientEndpoint
public boolean close()
{
try
{
if(this.container != null amp;amp; this.container instanceof LifeCycle) {
logger.trace("stoping container...");
((LifeCycle) this.container).stop();
}
this.session.close();
return true;
}
catch (Exception e)
{
logger.trace("Exception occured while closing the connection",e);
return false;
}
}
код: вызов метода close из другого класса
public closeConnection(){
this.wc.close();
System.exit(1);
}
Приветствуется любая помощь 🙂
Ответ №1:
Вы пытаетесь вызвать closeConnection
или close
из потока, который принадлежит контейнеру или пулу потоков / исполнителю контейнера?
Кроме того, как только контейнер будет остановлен, все сеансы тоже будут остановлены.
Изменение @ClientEndpoint
close()
должно быть …
public void close()
{
try
{
this.session.close();
}
catch (Exception e)
{
logger.trace("Exception occured while closing the connection",e);
}
}
И сделайте closeConnection()
просто…
public closeConnection()
{
LifeCycle.stop(this.wc.getContainer());
System.exit(1);
}
Рабочий пример этого можно найти на
https://github.com/joakime/javaxwebsocket-client-returncode
В котором есть код…
App.java
package org.eclipse.jetty.demo;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.WebSocketContainer;
import org.eclipse.jetty.util.component.LifeCycle;
public class App
{
private static final App MAIN_INSTANCE = new App();
private WebSocketContainer client;
public static void main(String[] args) throws IOException, DeploymentException, URISyntaxException
{
App.MAIN_INSTANCE.connect();
}
public static void stop(int returnCode)
{
// Trigger stop from thread that does not belong to Container.
new Thread(() ->
{
LifeCycle.stop(App.MAIN_INSTANCE.client);
System.exit(returnCode);
}).start();
}
private WebSocketContainer getClientContainer()
{
if (client == null)
client = ContainerProvider.getWebSocketContainer();
return client;
}
public void connect() throws IOException, DeploymentException, URISyntaxException
{
URI echoUri = URI.create("wss://echo.websocket.org");
ClientEndpointConfig clientEndpointConfig = ClientEndpointConfig.Builder.create()
.configurator(new OriginServerConfigurator(echoUri))
.build();
EchoEndpoint echoEndpoint = new EchoEndpoint();
getClientContainer().connectToServer(echoEndpoint, clientEndpointConfig, echoUri);
System.out.printf("Connected to : %s%n", echoUri);
}
}
EchoEndpoint.java
package org.eclipse.jetty.demo;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
/**
* Basic Echo Client Endpoint
*/
public class EchoEndpoint extends Endpoint implements MessageHandler.Whole<String>
{
private Session session;
@Override
public void onClose(Session session, CloseReason closeReason)
{
System.out.printf("Connection closed: Session.id=%s - %s%n", session.getId(), closeReason);
this.session = null;
}
@Override
public void onOpen(Session session, EndpointConfig config)
{
System.out.printf("Got open: Session.id=%s%n", session.getId());
this.session = session;
this.session.addMessageHandler(this);
try
{
session.getBasicRemote().sendText("Hello");
session.getBasicRemote().sendText("How are things?");
session.getBasicRemote().sendText("Thanks for the conversation.");
}
catch (Throwable t)
{
t.printStackTrace();
}
}
@Override
public void onMessage(String msg)
{
System.out.printf("Got msg: "%s"%n", msg);
if (msg.contains("Thanks"))
{
App.stop(1);
}
}
@Override
public void onError(Session session, Throwable cause)
{
cause.printStackTrace();
}
}
Комментарии:
1. Спасибо @Joakim Erdfelt, но это не сработало. Поток не принадлежит потоку контейнера, я думаю, потому что, учитывая, что у меня есть моя реализация @ clientendpoint в классе A и из класса B (программа содержит основной метод), я создаю объект класса A и, в конечном итоге, я создаю контейнер в конструкторе класса A .
2. Это работает. поверьте мне. 🙂 Я обновил ответ и даже ссылался на пример проекта, который это делает.
3. Это было освещено @Joakim Erdfelt. Но здесь ` новый поток(() -> { LifeCycle.stop (App.MAIN_INSTANCE.client); System.exit(returnCode); }).start();` единственное отличие заключается в остановке контейнера в новом потоке. Какая-либо причина, стоящая за этим?
4. Причина в том, что, как указано в ответе, вы не можете остановить жизненный цикл из потока, который управляется этим жизненным циклом. Это просто гарантирует, что остановка контейнера произойдет в другом потоке. Поскольку в примере приложения показано, что оно останавливается во время получения onMessage, я знаю, что это всегда находится в потоке, управляемом жизненным циклом этого контейнера.
5. Большое спасибо!! @Joakim Erdfelt