【问题标题】:Connect to Web-Socket-Server at runtime from back-end java class在运行时从后端 java 类连接到 Web-Socket-Server
【发布时间】:2017-01-20 06:09:28
【问题描述】:

我已经使用 spring 实现了以下 Web-Socket-Server。我们不想使用 STOMP 和 JSocks。

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(new WebSocketServerHandler(), "/websocket/user/{userId}");
  }

}




@Service
public class WebSocketServerHandler extends TextWebSocketHandler {

   private List<WebSocketSession> sessions = new ArrayList<WebSocketSession>();

   @Override
   public void handleTextMessage(WebSocketSession session, TextMessage message)
        throws Exception {

        session.sendMessage(message);           
   }

   @Override
   public void afterConnectionEstablished(WebSocketSession session) throws Exception {
     sessions.add(session);
   }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
      sessions = null;
    }

}

现在我可以从前端客户端(浏览器)成功连接到该 Web-Socket-Server。现在我想在运行时从我的一些 java 类连接到那个 Web-Socket-Server,然后想向那个 Web-Socket-Server 发送消息。有人知道我该怎么做吗?

我添加了一个测试 Rest Controller,如下所示:

 @RequestMapping(value = "/web-socket/message/{message}")
 public void sendMessage(@PathVariable("message") final String message) throws Exception {
   final String WS_URI = "ws://localhost:8080/web-socket/user/23";

   final CountDownLatch latch = new CountDownLatch(1);
   WebSocketClientHandler handler = new WebSocketClientHandler(latch);
   WebSocketClient client = new StandardWebSocketClient();
   WebSocketSession session = client.doHandshake(handler, WS_URI).get();
   session.sendMessage(new TextMessage(message));
   latch.await(5, TimeUnit.SECONDS);
   session.close();

}

我能够成功地向 websocket 服务器发送消息,仅是第一次通过使用 google rest 客户端调用此 Test RestController。如果我需要再次发送消息,那么我必须重新启动 tomcat 服务器。我在这里做什么有什么问题吗?

【问题讨论】:

    标签: java spring-websocket java-websocket


    【解决方案1】:

    spring-websocket 支持 WebSocket 客户端。基本合约是WebSocketClient。 Spring 没有实现整个 WebSocket 支持,但在其他实现之上提供了一个抽象层。常见的 Spring 客户端抽象是StandardWebSocketClient。一个简单的例子看起来像

    public static void main(String... args) throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        EchoHandler handler = new EchoHandler(latch);
        WebSocketClient client = new StandardWebSocketClient();
        WebSocketSession session = client.doHandshake(handler, ECHO_URL).get();
        session.sendMessage(new TextMessage("Hello World"));
        latch.await(5000, TimeUnit.SECONDS);
        session.close();
    }
    

    其中EchoHandler 是客户端WebSocketHandler(与服务器端相同)。

    public class EchoHandler extends TextWebSocketHandler {
    
        private final CountDownLatch latch;
    
        public EchoHandler(CountDownLatch latch) {
            this.latch = latch;
        }
    
        @Override
        public void handleTextMessage(WebSocketSession session, TextMessage message) {
            System.out.println("------- received client message ------");
            System.out.println(message.getPayload());
            System.out.println("--------- end client message ---------");
            latch.countDown();
        }
    }
    

    如果您在字符串环境中运行客户端,也可以将WebSocketClient 包装在WebSocketConnectionManager 中。如果您需要,这将为您提供一些生命周期助手。请参阅Spring Boot sample 中的示例。

    就依赖关系而言,就像我说的,Spring 没有实现整个 WebSocket 客户端支持,所以你需要一个实现。如果您在支持 WebSocket 的服务器中运行客户端,则无需添加任何内容。支持实现应该已经在服务器的类路径上。主要支持的 WebSocket 实现有 Jetty、Tomcat、Undertow(主要是 Wildfly 或独立的 Undertow)、Tyrus(即 Glassfish、WebLogic)。

    如果您在独立应用程序中运行客户端,则需要添加 WebSocket 实现。不幸的是,根据我的测试,没有一个实现提供完整的可操作的“仅客户端”jar。他们要么需要,要么已经引入了完整的(包括服务器)实现。因此,仅使用客户端,仍然需要拉入一堆服务器 jar。这是我从测试中得出的结论

    人人共享

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
        <version>${websocket.version}</version>
    </dependency>
    

    雄猫

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-websocket</artifactId>
        <version>${tomcat.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>${tomcat.version}</version>
    </dependency>
    

    暗流

    <dependency>
        <groupId>io.undertow</groupId>
        <artifactId>undertow-websockets-jsr</artifactId>
        <version>${undertow.version}</version>
    </dependency>
    

    泰鲁斯

    <!-- tyrus-client is pulled in by this. -->
    <dependency>
        <groupId>org.glassfish.tyrus</groupId>
        <artifactId>tyrus-server</artifactId>
        <version>${tyrus.version}</version>
    </dependency>
    

    码头

    <dependency>
        <groupId>org.eclipse.jetty.websocket</groupId>
        <artifactId>websocket-client</artifactId>
        <version>${jetty.version}</version>
    </dependency>
    

    对于 Jetty,它不使用标准的 Java WebSocket API,因此在StandardWebSocketClient 中没有使用它。你需要这样做

    JettyWebSocketClient client = new JettyWebSocketClient();
    client.start();
    

    上面的一切都是一样的。

    我只是查看了 Spring 源代码以了解它们使用的所有不同依赖项。您可以检查一下并使用依赖项。也许有不同的更有效(更轻)的依赖组合仍然可以工作。以上只是我测试并能够开始工作的内容。

    【讨论】:

    • 非常感谢。 “client.doHandshake(handler, ECHO_URL).get();”产生一个新线程?如果是,我们如何停止该线程。因为我创建了一个 RestController 并且能够使用 Google Restclient 发送消息,但是当我第二次尝试发送消息时,没有成功。每次我需要发送消息时,我都必须重新启动 tomcat 服务器。
    • 我的示例只是基于您的回显服务器示例。我不确定你是如何实现你的实际服务器的以及你想要完成什么,所以很难说问题是什么。
    猜你喜欢
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    • 1970-01-01
    相关资源
    最近更新 更多