使用标准 JSR356 WebSocket 客户端的连接超时
Connection timeout using standard JSR356 WebSocket client
我有一个连接到远程 websocket 服务器的 Java 应用程序。作为客户,我使用的是标准 Java EE JSR356 WebSocket API:
javax.websocket.WebSocketContainer.connectToServer(...)
但是,我还没有找到使用此 API 指定连接超时的方法。当我调用 connectToServer(...) 方法时,它会阻塞直到建立连接(这可能永远不会发生)。
有没有办法使用标准 API 指定连接超时?如果没有,是否有任何解决方法?
不幸的是,JSR 356 - WebSocket API for Java. You will need to use implementation feature, such as HANDSHAKE_TIMEOUT in Tyrus(参考实现)没有公开这一点。其他实现很可能会有类似的东西。
WEBSOCKET_SPEC, so you can add one if you want (I was able to find only issue which is mentioning SSL properties - WEBSOCKET_SPEC-210 中似乎还没有关于此的工单。
我自己刚刚开始工作。如果您通过 Future 构造调用 connectToServer,则可以在 get() 方法中使用超时。
您需要一个线程池:
private final ExecutorService pool = Executors.newFixedThreadPool(10);
函数如下:
private Future<Session> asyncConnectToServer(Object annotatedEndpointInstance, URI uri) {
return pool.submit(new Callable<Session>() {
@Override
public Session call() throws Exception {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
return(container.connectToServer(annotatedEndpointInstance, uri));
} catch (DeploymentException | IOException | IllegalStateException e) {
//throw new RuntimeException(e);
return(null);
}
}
});
}
你是这样称呼它的:
public webSocketClientEndpoint(URI endpointURI, long timeout) {
final Future<Session> futureSes = asyncConnectToServer(this, endpointURI);
try {
Session ses = futureSes.get(timeout, TimeUnit.MILLISECONDS);
} catch(InterruptedException | ExecutionException | TimeoutException e) {
System.out.println("Time out...");
}
}
您可以简单地覆盖 WsWebSocketContainer 中的 connectToServer 方法
public class WsWebSocketContainer2 extends WsWebSocketContainer {
@Override
public Session connectToServer(Object pojo, URI path) throws DeploymentException {
ClientEndpoint annotation = pojo.getClass().getAnnotation(ClientEndpoint.class);
if (annotation == null) {
throw new DeploymentException("wsWebSocketContainer.missingAnnotation");
}
Endpoint ep = new PojoEndpointClient(pojo, Arrays.asList(annotation.decoders()));
Class<? extends ClientEndpointConfig.Configurator> configuratorClazz = annotation.configurator();
ClientEndpointConfig.Configurator configurator = null;
if (!ClientEndpointConfig.Configurator.class.equals(configuratorClazz)) {
try {
configurator = configuratorClazz.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new DeploymentException("wsWebSocketContainer.defaultConfiguratorFail", e);
}
}
ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
// Avoid NPE when using RI API JAR - see BZ 56343
if (configurator != null) {
builder.configurator(configurator);
}
ClientEndpointConfig config = builder.decoders(Arrays.asList(annotation.decoders())).encoders(Arrays.asList(annotation.encoders()))
.preferredSubprotocols(Arrays.asList(annotation.subprotocols())).build();
Map<String, Object> userProperties = config.getUserProperties();
userProperties.put(Constants.IO_TIMEOUT_MS_PROPERTY, 999999);
return connectToServer(ep, config, path);
}
}
我有一个连接到远程 websocket 服务器的 Java 应用程序。作为客户,我使用的是标准 Java EE JSR356 WebSocket API:
javax.websocket.WebSocketContainer.connectToServer(...)
但是,我还没有找到使用此 API 指定连接超时的方法。当我调用 connectToServer(...) 方法时,它会阻塞直到建立连接(这可能永远不会发生)。
有没有办法使用标准 API 指定连接超时?如果没有,是否有任何解决方法?
不幸的是,JSR 356 - WebSocket API for Java. You will need to use implementation feature, such as HANDSHAKE_TIMEOUT in Tyrus(参考实现)没有公开这一点。其他实现很可能会有类似的东西。
WEBSOCKET_SPEC, so you can add one if you want (I was able to find only issue which is mentioning SSL properties - WEBSOCKET_SPEC-210 中似乎还没有关于此的工单。
我自己刚刚开始工作。如果您通过 Future 构造调用 connectToServer,则可以在 get() 方法中使用超时。
您需要一个线程池:
private final ExecutorService pool = Executors.newFixedThreadPool(10);
函数如下:
private Future<Session> asyncConnectToServer(Object annotatedEndpointInstance, URI uri) {
return pool.submit(new Callable<Session>() {
@Override
public Session call() throws Exception {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
return(container.connectToServer(annotatedEndpointInstance, uri));
} catch (DeploymentException | IOException | IllegalStateException e) {
//throw new RuntimeException(e);
return(null);
}
}
});
}
你是这样称呼它的:
public webSocketClientEndpoint(URI endpointURI, long timeout) {
final Future<Session> futureSes = asyncConnectToServer(this, endpointURI);
try {
Session ses = futureSes.get(timeout, TimeUnit.MILLISECONDS);
} catch(InterruptedException | ExecutionException | TimeoutException e) {
System.out.println("Time out...");
}
}
您可以简单地覆盖 WsWebSocketContainer 中的 connectToServer 方法
public class WsWebSocketContainer2 extends WsWebSocketContainer {
@Override
public Session connectToServer(Object pojo, URI path) throws DeploymentException {
ClientEndpoint annotation = pojo.getClass().getAnnotation(ClientEndpoint.class);
if (annotation == null) {
throw new DeploymentException("wsWebSocketContainer.missingAnnotation");
}
Endpoint ep = new PojoEndpointClient(pojo, Arrays.asList(annotation.decoders()));
Class<? extends ClientEndpointConfig.Configurator> configuratorClazz = annotation.configurator();
ClientEndpointConfig.Configurator configurator = null;
if (!ClientEndpointConfig.Configurator.class.equals(configuratorClazz)) {
try {
configurator = configuratorClazz.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new DeploymentException("wsWebSocketContainer.defaultConfiguratorFail", e);
}
}
ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
// Avoid NPE when using RI API JAR - see BZ 56343
if (configurator != null) {
builder.configurator(configurator);
}
ClientEndpointConfig config = builder.decoders(Arrays.asList(annotation.decoders())).encoders(Arrays.asList(annotation.encoders()))
.preferredSubprotocols(Arrays.asList(annotation.subprotocols())).build();
Map<String, Object> userProperties = config.getUserProperties();
userProperties.put(Constants.IO_TIMEOUT_MS_PROPERTY, 999999);
return connectToServer(ep, config, path);
}
}