WebSocketSession.send 不做任何事情

Posted

技术标签:

【中文标题】WebSocketSession.send 不做任何事情【英文标题】:WebSocketSession.send does not do anything 【发布时间】:2021-12-30 12:59:39 【问题描述】:

我正在编写一个游戏,当一个玩家结束其回合时,我想通知对手轮到他玩了。

所以我将 WebSocketSessions 存储在“Player”类中,所以我只需要获取一个玩家的实例就可以访问他的 websocketsession。

问题是当我使用存储在“播放器”实例中的 websocketsession 的“发送”方法时,什么都没有发生。

这是我将 WebSocketSession 存储在播放器对象中的代码,它实际上从前端正确接收消息,并且能够发回消息并且它可以工作:

@Component("ReactiveWebSocketHandler")
public class ReactiveWebSocketHandler implements WebSocketHandler 
    
    @Autowired
    private AuthenticationService authenticationService;
    
    @Override
    public Mono<Void> handle(WebSocketSession webSocketSession) 

        Flux<WebSocketMessage> output = webSocketSession.receive()
                .map(msg -> 
                    String payloadAsText = msg.getPayloadAsText();
                    Account account = authenticationService.getAccountByToken(payloadAsText);
                    Games.getInstance().getGames().get(account.getIdCurrentGame()).getPlayerById(account.getId()).setSession(webSocketSession);
                    return "WebSocketSession id: " + webSocketSession.getId();
                )
                .map(webSocketSession::textMessage);

        return webSocketSession
                .send(output);
    

这是我用来通知对手玩家轮到该玩的代码了,“opponentSession.send”方法似乎没有产生任何结果,没有错误消息,看起来我什么也没收到前端。会话的 ID 与 handle 方法中的相同,所以我认为会话对象很好,当我进行测试时,websocket 会话也已打开并准备就绪:

@RequestMapping(value = "/game/endTurn", method = RequestMethod.POST)
GameBean endTurn(
        @RequestHeader(value = "token", required = true) String token) 
    ObjectMapper mapper = new ObjectMapper();

    Account account = authenticationService.getAccountByToken(token);
    gameService.endTurn(account);

    Game game = gameService.getGameByAccount(account);
    //GameBean opponentGameBean = game.getOpponentGameState(account.getId());
    //WebSocketMessage webSocketMessage = opponentSession.textMessage(mapper.writeValueAsString(opponentGameBean));
    WebSocketSession opponentSession = game.getPlayerById(game.getOpponentId(account.getId())).getSession();
    WebSocketMessage webSocketMessage = opponentSession.textMessage("test message");

    opponentSession.send(Mono.just(webSocketMessage));

    return gameService.getGameStateByAccount(account);


您可以在屏幕截图中看到,handle 方法工作正常,我可以发送和接收消息。 Websocket input and output

有人知道我怎样才能让对手Session.send 方法正常工作,以便我可以在前端接收消息吗?

【问题讨论】:

你不应该混合使用 webflux 和 spring web。如果这样做,spring 服务器将启动一个 spring web 应用程序,而您将无法从响应式应用程序中获得好处。 【参考方案1】:

您正在为您的 websocket 使用响应式堆栈,WebSocketSession#send 返回一个 Mono&lt;Void&gt;,但您没有订阅此 Mono(您只是组装了它),所以在订阅它之前什么都不会发生。

在您的端点中,您似乎没有使用 webflux,因此您处于同步世界中,因此您别无选择,只能block

opponentSession.send(Mono.just(webSocketMessage)).block();

如果您使用的是 webflux,那么您应该更改您的方法以返回 Mono 并执行以下操作:

return opponentSession.send(Mono.just(webSocketMessage)).then(gameService.getGameStateByAccount(account));

如果您对此不熟悉,请查看projectreactor 和WebFlux

【讨论】:

感谢您的回答! “块”方法导致错误,这是因为我认为我正在混合 REST api 和 webflux。我用过:对手Session.send(Mono.just(webSocketMessage)).subscribe();它工作得很好。非常感谢您的帮助,我想我需要研究反应堆项目,因为我有点难以理解反应式编程的工作原理。 block 方法在某些情况下会抛出错误。像这样订阅可以是一种替代方法,但您可能会在实际发送 webSocketMessage 之前返回您的 GameBean

以上是关于WebSocketSession.send 不做任何事情的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV destroyWindow() 不做任何事情。

ListView onItemClickListener 不做任何事情

npm update 不做任何事情

下拉框更改时提交表单 - 不做任何事情

TabControl.VerticalAlignment = 拉伸不做任何事情

密码系统不做任何事情