java - 使用 WebSockets 实现 WebRTC 信令

标签 java javascript jakarta-ee websocket webrtc

为了使用 WebRTC API 连接点对点通信,您需要实现信令。信令需要双向通信 channel 才能工作。 WebSockets 是双向通信 channel 。我想使用 WebSockets 来实现信令,但是,我不知道如何处理它。我在网上找到的所有内容都只是讨论了您可以使用的不同的两种方式 channel ,而不是提供有关如何使用它们的示例。

我在客户端使用 JavaScript,在服务器端使用 Java。那么,我将如何使用 WebSockets 实现信令?

最佳答案

这是我想出的方法。我还没有测试代码,所以,我不确定它是否有效。另外,我怀疑这是否有效。如果您有更好的解决方案,请查看我的代码中的问题,或任何建议,请随时详细说明。这背后的想法是让 WebSocket 服务器端点过滤消息并将它们发送给适当的用户。

  • 首先,我使用预先确定的用户 ID 向客户端发送消息。 WebSocket 服务器端点只知道包含 session ID 的 session 对象(不能更改;没有设置方法)。为了链接 session ID 和用户 ID,我需要一个数据库表(比将其保存在内存中更可靠)。

  • 然后,从客户端发送到 WebSocket 服务器端点的第一条消息将包含该用户的 ID。这将与 session ID 一起映射到数据库,客户端将被视为“已连接”。当然,这是在实际连接到 WebSocket 之后发生的。

  • 现在,一旦“连接”,我们就可以向另一个用户发送(信号)消息,只要我们知道他们的用户 ID(我假设我们知道)。 WebSocket 服务器端点根据数据库检查接收者用户 ID 以找到他们的 session ID。一旦找到,就可以发送消息。

  • 最后,在客户端,我们可以破译消息并将适当的消息发回(使用与上述相同的过程)。

因此,如前所述,我们需要一个用于客户端 session 和用户 ID 的数据库表。由于我将 Java 用于所有后端代码,因此我们将通过创建一个实体类来保存属性来使用 ORM(对象关系映射)。像这样:

    @Entity
    public class WebSocketUser {
        @Id@GeneratedValue
        private long id;
        private long userId;
        private long sessionId;

        //constructors, getters and setters
    }

现在,我们可以创建服务器端点类:

    @ServerEndpoint("/SignalingServerEndpoint")
    public class SignalingServerEndpoint {
        //these class variables will be useful for 
        //access to the database and such
        private EntityManagerFactory emf;
        private EntityManager em;
        private EntityTransaction tx;
        private TypedQuery<WebsocketUser> query;
        private WebsocketUser wsu;

因为我们不在 EJB 中,所以我们必须像在应用程序托管环境中一样控制实体管理器。将 onOpen 和 onClose 方法添加到 Websocket:

    @OnOpen
    public void open(Session session, Endpoint config){
        emf = Persistence.createEntityManagerFactory(""); //TODO add persistence unit reference here
        em = emf.createEntityManager();
        tx = em.getTransaction();
    }

    @OnClose
    public void close(Session session, CloseReason reason){
        //if session is closing and information still exists in the database; remove it
        if (!wsu.equals(null)){
            tx.begin();
            em.remove(wsu);
            tx.commit();
        }
        em.close();
        emf.close();
    }

接下来,在 WebSocket Server Endpoint 的 onMessage 方法中,我们过滤消息。我选择以 JSON 格式发送消息。这使您可以轻松破译信息(我使用了 org.json 库)。 onMessage 方法:

    @OnMessage
    public void message(Session session, String msg){
        try {
            JSONObject obj = new JSONObject(msg);
            if (!obj.has("toUserId")){
                //adding user to the database, so they can access their session ID with their user ID
                WebsocketUser wsu = new WebsocketUser(obj.getLong("userId"), session.getId());
                tx.begin();
                em.persist(wsu);
                tx.commit();
            }else if (obj.has("toUserId")){
                //message to be sent to the user with the specified user ID
                //get session ID from database
                query = em.createQuery("SELECT u FROM WebsocketUser u WHERE u.userId = " + obj.getLong("toUserId"), WebsocketUser.class);
                wsu = (WebsocketUser) query.getSingleResult();
                Set<Session> sessions = session.getOpenSessions();
                for (Iterator<Session> i = sessions.iterator(); i.hasNext();){
                    Session s = i.next();
                    if (s.getId().equals(wsu.getSessionId())){
                        s.getAsyncRemote().sendText(obj.getString("message"));
                        break;
                    }
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

最后,我们只剩下客户端(javascript)了。创建 WebSocket 变量:

    var signalingSocket = new WebSocket("/SignalingServerEndpoint"); //TODO need the full and correct path to the WebSocket

现在,对于将消息发送到“连接”到 WebSocket 服务器端点的方法:

    function connect(){
        var msg = {
            "userId": userId
        };
        signalingSocket.send(JSON.stringify(msg));

最后,我们所拥有的只是客户端的 onMessage 方法(它将解密消息并可能将信息发送到其他客户端)和所有实际的信号代码(ICE 服务器、约束等)。我不会深入研究所有的信令工作,但有一个很好的教程 here.我希望这可以帮助其他面临类似问题的人。正如我所说,我还没有测试代码,所以我不确定它是否有效。另外,我非常怀疑这是否有效。但这至少是一个开始。

关于java - 使用 WebSockets 实现 WebRTC 信令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25019945/

相关文章:

java - 我的 Game of Life 程序文件阅读器出现问题

java - 使用 Java EE 6 Bean 验证

java - 设置在另一个类中分配的私有(private)变量的问题

javascript - js错误的字符串输出

java - 如何使 activemq 真正可靠?当broker断开连接时消息丢失

java - 是否应该缓存 InitialContext 实例?

jakarta-ee - 如何在 jBoss 上唯一化上下文根

java - 服务器(java)无法使用 SSL 连接从客户端(c#)接收 XML

JavaScript $.GET 未通过

javascript - 比较两个 object.attribute 还是比较两个对象更快?