Tyrus WebSocket客户端@OnMessage从未被调用 - Storj开源项目

9
我正在开发一个开源项目Storj,并编写连接到Node.js Websocket后端的Java客户端。该客户端使用Tyrus。通信应按以下方式进行:
  • 连接
  • 客户端发送身份验证令牌(文本)。
  • 服务器返回文件(二进制)。
  • 服务器关闭连接。
我的问题在于我的@OnMessage从未被调用。我已经尝试使用在线的简单JavaScript客户端以及相同令牌的相同URL,但是没有成功: https://www.websocket.org/echo.html 虽然使用简单的JavaScript客户端可以得到响应,但说明Java项目存在问题。
在能够下载文件之前,在较早的阶段,我可以上传文件而不会出现任何问题。 但是,该步骤不需要调用@OnMessage(它只是上传文件,然后服务器断开连接并显示一条消息),因此我不确定我的@OnMessage是否正常工作。
这是Websocket的相关代码(也可在Github上找到): https://github.com/NutterzUK/storj-java-bridge-client/blob/master/storj-client/src/main/java/storj/io/client/websockets/WebsocketFileRetriever.java
package storj.io.client.websockets;

import com.google.gson.Gson;
import storj.io.restclient.model.FilePointer;

import javax.websocket.*;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;

/**
 * Created by steve on 12/07/2016.
 */
@ClientEndpoint
public class WebsocketFileRetriever {

    private Logger logger = Logger.getLogger(this.getClass().getName());
    private Gson gson = new Gson();
    private FilePointer filePointer;
    private File outputFile;
    private AuthorizationModel authModel;
    private CountDownLatch latch;

    public WebsocketFileRetriever(FilePointer filePointer, File outputFile, CountDownLatch latch){
        this.filePointer = filePointer;
        this.latch = latch;
        this.outputFile = outputFile;
        authModel = new AuthorizationModel();
        authModel.setToken(filePointer.getToken());
        authModel.setOperation(filePointer.getOperation());
        authModel.setHash(filePointer.getHash());
    }

    @OnMessage
    public void onMessage(String s){
        logger.info("Received ... " + s);
    }

    @OnMessage
    public void onMessage(ByteBuffer message, Session session) {
        logger.info("Received ...." + message);
    }

    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        logger.info("Opened");
        try {
            session.getBasicRemote().sendText(gson.toJson(authModel), true);
        } catch (IOException e) {
            e.printStackTrace();
        }

        logger.info("sent: " + gson.toJson(authModel));
    }

    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        logger.info("Closed Websocket: " + closeReason.getCloseCode() + " " + closeReason.getReasonPhrase());
        //latch.countDown();
    }

    @OnError
    public void onError(Session session, Throwable t) {
        t.printStackTrace();
    }
}

以下是启动此websocket的代码,可在此处找到: https://github.com/NutterzUK/storj-java-bridge-client/blob/master/storj-client/src/main/java/storj/io/client/DefaultStorjClient.java :

        CountDownLatch latch;
        latch = new CountDownLatch(1);
        ClientManager wsClient = ClientManager.createClient();
        try {
            wsClient.setDefaultMaxBinaryMessageBufferSize(Integer.MAX_VALUE);
            wsClient.setDefaultMaxTextMessageBufferSize(Integer.MAX_VALUE);
            logger.info("CONNECTING TO: " + "ws://" + pointer.getFarmer().getAddress() + ":" + pointer.getFarmer().getPort());
            final ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();

            wsClient.connectToServer(new WebsocketFileRetriever(pointer, encryptedOutputFile, latch), cec, new URI("ws://" + pointer.getFarmer().getAddress() + ":" + pointer.getFarmer().getPort()));
            latch.await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

我还尝试将Tyrus升级到最新版本,但结果仍然相同。有什么想法吗?

此代码的输出为:

    Aug 25, 2016 8:55:31 PM storj.io.client.DefaultStorjClient downloadFile
INFO: CONNECTING TO: ws://164.storj.eu:8607
Aug 25, 2016 8:55:35 PM storj.io.client.websockets.WebsocketFileRetriever onOpen
INFO: Opened
Aug 25, 2016 8:55:35 PM storj.io.client.websockets.WebsocketFileRetriever onOpen
INFO: sent: {"token":"06c36d4bac4f07ee1751068b5b2230f22e884b38","hash":"837b79bec927a1d8fa7fedd2ea0bb276e0d86e0f","operation":"PULL"}
Aug 25, 2016 8:56:11 PM storj.io.client.websockets.WebsocketFileRetriever onClose
INFO: Closed Websocket: NORMAL_CLOSURE Closing

发送消息后,它会在@OnClose发送“NORMAL_CLOSURE”消息之前挂起一段时间。
更新:一个非常简单的重现问题的方法是运行以下代码:
我已经在git存储库中添加了测试用户名和密码,因此可以在这里使用代码:https://github.com/NutterzUK/storj-java-bridge-client 要运行它,您只需要运行storj.io.client.main.MainTest
快速浏览一下它的操作。首先,它将发送一些HTTP请求以获取令牌。然后它将使用该令牌通过WebSocket连接到某个机器,并将该令牌作为文本发送。作为响应,它应该接收到一个文件(以字节形式)。
在连接之前,它将打印出令牌和即将连接的地址。它将被挂起一段时间,然后被关闭,永远不会调用任何onMessage方法。为了测试,在那里放置一个System.exit(取消注释DefaultStorjClient.java中的第152行),它将无法连接,因此您可以在另一个客户端中使用该令牌。我已经测试过使用https://www.websocket.org/echo.html(确保您的浏览器允许不安全的URL,因为它不是“wss”,在Chrome中,您需要单击右上角的屏蔽。我可以看到服务器确实有响应:Image showing the blob being received 这表明一个Blob确实作为文本消息的响应发送,但是Tyrus中的@OnMessage从未被触发。

JS服务器将此发送为“blob”,这可能与问题有关吗? - ThePerson
有测试用例是很好的事情。我的意思是...虽然我已经连接到了服务,但我无法让它发送文件,所以我无法测试Tyrus是否能从你的服务器接收消息。无论如何,Tyrus也可以与回声服务器一起使用,因此那并不是一个真正有用的测试(只需将tyrus客户端指向“ws:// echo.websocket.org”并发送消息即可)。 - Pavel Bucek
谢谢。是的,它可以与回声服务器一起工作,但我不认为回声服务器会发送回字节。我认为如果你在storj.io上创建一个帐户(免费),你可以运行“testmain”并发送一个文件进行测试。这都在github上了,不幸的是我真的很困惑为什么会发生这种情况,所以我将在7小时后添加一个赏金来解决这个问题。 - ThePerson
我可以创建一个测试账户,然后在这里提供用户名和密码,以免其他人再次操作。我会这样做并将其添加到问题中,同时我还会更新TestMain函数,只下载单个文件以突出问题。 - ThePerson
我已经在描述中添加了“更新:运行此以查看问题的非常简单的方法”。它应该很容易重现,我还提供了来自回声测试客户端的输出,该客户端可以调用相同的WebSocket服务器并返回一个blob。一旦SO允许我,我将添加赏金,在6小时内。 - ThePerson
1个回答

2
最终我转向了TallNate,这个问题就不存在了。
我发现在计时后,它总是在30秒后断开连接。通常响应时间比30秒更快,所以我不确定为什么会在那时挂起然后断开连接。我尝试在Tyrus中设置超时时间,但仍然在30秒标记处断开连接。最终我尝试了TallNate,看看是否可以在那里设置超时时间...然后它直接运行了。 https://github.com/TooTallNate/Java-WebSocket/wiki/Drafts

你找到实际原因了吗?也许另一个客户端只是定期发送ping(在Tyrus中也支持,参见https://tyrus.java.net/apidocs/1.13/org/glassfish/tyrus/core/TyrusSession.html#setHeartbeatInterval(long))。 - Pavel Bucek

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