我目前正在通过Java中的Websocket服务器为STOMP编写测试回显客户端。但是我注意到连接在某种程度上是不可预测的,因为它通常在收到消息之前关闭,因此客户端产生异常
java.io.IOException: java.util.concurrent.ExecutionException: java.io.IOException: Unable to write the complete message as the WebSocket connection has been closed
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:282) ~[tomcat-embed-websocket-8.0.30.jar:8.0.30]
at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:584) [tomcat-embed-websocket-8.0.30.jar:8.0.30]
这是我的简单测试客户端
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = Application.class)
@WebIntegrationTest(randomPort = true)
public class WebSocketConfigurationIT {
@Value("${local.server.port}")
private int port;
private SockJsClient sockJsClient;
@Before
public void setUp() {
final WebSocketTransport webSocketTransport = new WebSocketTransport(new StandardWebSocketClient());
final RestTemplateXhrTransport restTemplateXhrTransport = new RestTemplateXhrTransport(new RestTemplate());
sockJsClient = new SockJsClient(Lists.newArrayList(webSocketTransport, restTemplateXhrTransport));
}
@Test
public void testEcho() throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(1);
StompSessionHandler stompSessionHandler = new StompSessionHandlerAdapter() {};
WebSocketStompClient webSocketStompClient = new WebSocketStompClient(sockJsClient);
webSocketStompClient.setDefaultHeartbeat(new long[]{0, 0});
webSocketStompClient.setMessageConverter(new MappingJackson2MessageConverter());
ListenableFuture<StompSession> connect = webSocketStompClient.connect("ws://localhost:{port}/api/ws/media/socket", stompSessionHandler, port);
StompSession session = connect.get();
String message = UUID.randomUUID().toString();
log.debug("sending {}", message);
session.send("/echo/" + message, null);
session.subscribe("/topic/echo/" + message, new StompFrameHandler() {
@Override
public Type getPayloadType(final StompHeaders headers) {
return String.class;
}
@Override
public void handleFrame(final StompHeaders headers, final Object payload) {
log.debug("received {}", payload);
assertEquals(message, payload);
countDownLatch.countDown();
}
});
// wait for messange being echoed
if (!countDownLatch.await(15, TimeUnit.SECONDS)) {
fail("message not received");
}
}
@Controller
public static class EchoController {
@MessageMapping("/echo/{message}")
public String echo(SimpMessageHeaderAccessor simpMessageHeaderAccessor, @DestinationVariable("message") String message) {
log.debug("header {}", simpMessageHeaderAccessor);
log.debug("echoed {}", message);
return message;
}
}
}
和配置类
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/api/ws/media/socket").withSockJS();
}
@Override
public void configureMessageBroker(final MessageBrokerRegistry registry) {
super.configureMessageBroker(registry);
//registry.setApplicationDestinationPrefixes("/");
registry.enableSimpleBroker("/topic", "/queue");
}
}