使用标准JSR356 WebSocket客户端连接超时

5

我有一个Java应用程序,连接到远程websocket服务器。作为客户端,我使用标准的Java EE JSR356 WebSocket API

javax.websocket.WebSocketContainer.connectToServer(...)

然而,使用这个API我还没有找到指定连接超时的方法。当我调用connectToServer(...)方法时,它会一直阻塞直到建立连接(这可能永远不会发生)。

是否有一种使用标准API来指定连接超时的方法?如果没有,有什么解决方法吗?

3个回答

3

1
谢谢您的回答,我已经为此创建了一个JIRA问题:https://java.net/jira/browse/WEBSOCKET_SPEC-234 - Tihomir Meščić

1
你可以在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);
    }
}

这并不是理想的解决方案,但是通过以下更改可以实现:timeout用户属性值必须为字符串。userProperties.put(Constants.IO_TIMEOUT_MS_PROPERTY, "999999"); - Matt

-2

我刚刚自己解决了这个问题。如果你通过Future构造调用connectToServer,你可以在get()方法中使用timeout。

你需要一个线程池:

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...");
        }
    }

Ref: https://dzone.com/articles/javautilconcurrentfuture

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get(long,%20java.util.concurrent.TimeUnit)


欢迎提供潜在解决方案的链接,但请添加链接周围的上下文,以便其他用户了解它是什么以及为什么存在。始终引用重要链接的最相关部分,以防目标站点无法访问或永久离线。请注意,仅仅是外部网站链接的答案可能是为什么和如何删除某些答案?的原因之一。 - FelixSFD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接