Kurento JSON-RPC 中文文档

唐星晖
2023-12-01

KURENTO JSON-RPC 中文文档

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/popboy100/article/details/85049569

版本

Kurento V6.6.1-dev

描述

本文档描述了Kurento项目中JSON-RPC客户端与服务端的实现。对于WebSocket协议的详细介绍超出了本文档的范围。但是,至少必须了解,HTTP仅用于初始握手阶段,而初始握手阶段依赖于HTTP的内置机制,去请求协议升级(或在本例中称为协议切换),如果服务器同意,则服务器响应的HTTP状态为101(正在切换协议)。假设握手成功,HTTP升级请求的底层TCP Socket将保持打开状态,客户端和服务端都可以通过Socket彼此发送消息。有关协议本身的信息,请参阅项目文档中的此页面

JSON-RPC v2.0规范所描述的那样,该协议意味着存在一个发出请求的客户端,并且存在一个处理这些请求的服务端。这与v1.0截然相反,后者使用的是Peer-to-Peer架构,其中两个Peer既是客户端又是服务端。

代码结构

Kurento已经实现了Java版本的JSON-RPC服务端,还有使用Java和Javascript实现的客户端。所有实现都托管在GitHub上:

Java实现包含具有以下模块的Maven项目:

Javascript实现包括:

Json-Rpc 服务端

这是JAVA实现的JSON-RPC服务端。它只支持v2.0,这意味着可以使用通知。然而,唯一可用的传输协议是WebSocket。它作为Maven artifact发布,允许开发人员简单易用的管理它作为依赖项,通过在其项目的pom中包含以下依赖项:

<dependency>
    <groupId>org.kurento</groupId>
    <artifactId>kurento-jsonrpc-server</artifactId>
    <version>6.6.1-SNAPSHOT</version>
</dependency>

服务端基于Spring Boot 1.3.0.RELEASE,使用非常简单,类似于Spring中WebSocketHandler的创建和配置。它基本上由服务器的配置和一个实现接收请求的处理类组成。下面的代码为JSON-RPC请求实现了一个处理,其中包含一个JsonObject作为参数数据类型。此处理将接收到的参数发回给客户端。由于请求处理总是返回一个响应,如果程序员没有故意这样做,库将自动发送一个空响应。在下面的示例中,如果请求没有调用echo方法,它将返回一个空响应:

import org.kurento.jsonrpc.DefaultJsonRpcHandler;
import org.kurento.jsonrpc.Transaction;
import org.kurento.jsonrpc.message.Request;

import com.google.gson.JsonObject;

public class EchoJsonRpcHandler extends DefaultJsonRpcHandler<JsonObject> {

    @Override
    public void handleRequest(Transaction transaction,
            Request<JsonObject> request) throws Exception {
        if ("echo".equalsIgnoreCase(request.getMethod())) {
            transaction.sendResponse(request.getParams());
        }
    }
}

该方法的第一个参数是Transaction,它表示客户端和服务端之间的消息交换。Transaction可用的方法(不包括重载),以及不同用法如下:

  • sendResponse: 将响应发送回客户端。
  • sendError: 将错误发送回客户端。
  • getSession: 返回分配给客户端的JSON-RPC会话。
  • startAsync: 如果程序员想要在handleRequest方法调用之外响应请求,可以使用这个方法来指示服务端暂时不响应。当请求需要很长时间处理且服务端未被锁定时,可以使用此方法。
  • isNotification: 评估接收到的消息是否是通知,在这种情况下,不应该响应它。

在方法handleRequest中,开发人员可以访问JSON-RPC请求(method、params、id或jsonrpc)的任何字段。这就是管理调用方法的地方。除了在该类中处理的方法外,服务端还处理以下特殊method值:

  • close: 客户端在优雅地关闭连接时发送此方法。这允许服务端关闭连接并释放资源。
  • reconnect: 已断开连接的客户端可以发出此消息附加到已存在的会话上。sessionId是强制性参数。
  • ping: 简单的ping-pong消息交换提供心跳机制。

***DefaultJsonRpcHandler***类是根据请求附带的有效负载进行泛化的。在前面的代码中,预期的有效负载是JsonObject,但也可以是普通字符串或任何其他对象。

为了使用Handler去配置基于WebSocket的JSON-RPC服务端,开发人员可以使用JsonRpcConfiguration,将上述WebSocket处理映射到特定的URL(本例中为http://localhost:8080/echo):

import org.kurento.jsonrpc.internal.server.config.JsonRpcConfiguration;
import org.kurento.jsonrpc.server.JsonRpcConfigurer;
import org.kurento.jsonrpc.server.JsonRpcHandlerRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;

@Import(JsonRpcConfiguration.class)
public class EchoServerApplication implements JsonRpcConfigurer {

    @Override
    public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) {
        registry.addHandler(new EchoJsonRpcHandler(), "/echo"); // “/echo” is the path relative to the server’s URL
    }

}

Session控制

连接到此服务器每个客户端都将被分配一个唯一的sessionId。这提供了session会话概念,可用通过该方式扩展为多个WebSocket会话。JSON-RPC会话,允许将一组属性绑定到一个特定的会话上。这使开发人员能够实现具有状态服务会话服务端的能力,这样用户可以在重连后恢复会话。在会话对象中有如下可用的方法:

  • getSessionId: 获取分配给此会话的ID。它可以用于跟踪会话,并将其注册到服务器中,并将其映射到其他资源。
  • getRegisterInfo: 由客户端在连接时设置的注册信息,服务端可以通过此方法访问注册新。
  • isNew: 如果消息是会话的第一条消息,则为true。
  • close: 优雅地关闭连接。
  • setReconnectionTimeout: 设置服务器在关闭会话之前等待重新连接的时间。
  • getAttributes: 返回会话中的属性映射。

Handlers处理

高级特性

注册handler时,有许多特性是可以配置的。这些可以通过DefaultJsonRpcHandler中的API进行设置:

  • withSockJS() - 启用SockJS作为WS库,如果升级失败,将回退为HTTP。客户端应该具有SockJS能力。更多信息
  • withLabel(String) - 添加处理请求时使用的标签。这允许在日志文件中有一个友好的名称,以便更容易地跟踪执行情况。
  • withPingWatchdog(true|false) - ping看门狗是一种监视心跳机制健康状况的功能,允许检测在预期时间内没有接收到常规ping消息的问题。出现这种问题则会通知服务端,尽管WebSocket连接可能仍然处于打开状态,但另一端的客户端却无法按预期工作。
  • withAllowedOrigins(String[]) - 默认情况下,只允许与应用程序服务的来源(主机和端口)相同的客户端进行连接,从而限制了集群和负载平衡功能。此方法接受一个字符串数组,该字符串数组为允许连接的来源。官方的Spring Boot文档提供了关于这方面的工作细节。

连接事件处理

该handler重写某些与连接事件相关的方法,现有的方法如下:

import org.kurento.jsonrpc.DefaultJsonRpcHandler;
import com.google.gson.JsonObject;

public class EchoJsonRpcHandler extends DefaultJsonRpcHandler<JsonObject> {

    // ...

    @Override
    public void afterConnectionEstablished(Session session) throws Exception {
        // Do something useful here
    }

    @Override
    public void afterConnectionClosed(Session session, String status)
            throws Exception {
        // Do something useful here
    }

    @Override
    public void handleTransportError(Session session, Throwable exception)
            throws Exception {
        // Do something useful here
    }

    @Override
    public void handleUncaughtException(Session session, Exception exception) {
        // Do something useful here
    }
}

Notifications通知

Notification是一个没有“id”成员的Request对象。作为通知的Request对象表示发送方对相应的Response对象不感兴趣,因此不需要返回响应对象。

根据定义,Notification是不可确认的,因为它们没有要返回的Response对象。因此,发送者不会发现任何错误(比如:“无效参数”、“内部错误”)。

服务器可以通过持有的session对象向连接的客户端发送通知。为此,在连接时需要存储每个客户端的Session对象。这可以通过重写handler的***afterConnectionEstablished ***方法来实现。

public class EchoJsonRpcHandler extends DefaultJsonRpcHandler<JsonObject> {

    public final Map<String, Session> sessions = new HashMap<>();

    @Override
    public void afterConnectionEstablished(Session session) {
        String clientId = (String) session.getAttributes().get("clientId");
        sessions.put(clientId, session);
    }

    @Override
    public void afterConnectionClosed(Session session, String status)
         throws Exception {
        String clientId = (String) session.getAttributes().get("clientId");
        sessions.remove(clientId);
    }

    // Other methods
}

会话如何与每个客户端配对取决于应用程序的业务逻辑。在本例中,我们假设会话包含一个clientId属性,该属性可用于唯一标识每个客户端。还可以使用sessionId,库将:term:UUID作为会话标识符,但它们对使用该库的应用程序没有意义。当客户端断开连接时,最好不要遗留已注册的会话,因此我们重写PostConnectionClosed方法,并在那里删除存储的Session对象。

通知通过已建立的会话发送给连接的客户端。同样,如何将会话映射到客户端,这超出了本文档的范围,因为它取决于应用程序的业务逻辑。假设handler对象位于相同的范围内,下面的代码片段将显示如何向特定客户端发送通知:

public void sendNotification(String clientId, String method, Object params)
    throws IOException {
  handler.sessions.get(clientId).sendNotification(method, params);
}

Java文档

Json-Rpc客户端

这是kurento-jsonrpc-server的Java客户端,或者其他任何实现JSON-RPC协议的WebSocket服务器。它允许Java程序通过JSON-RPC调用kurento-jsonrpc-server。也被发布为Maven的依赖项,可以将其添加到项目的pom:

<dependency>
    <groupId>org.kurento</groupId>
    <artifactId>kurento-jsonrpc-server</artifactId>
    <version>6.6.1-SNAPSHOT</version>
</dependency>

创建客户端

与服务器相反,客户端与框架无关,因此它可以用于常规的java应用程序、java EE、Spring…。创建一个向服务端发送请求的客户端是非常简单的。将服务器的URI传递给JsonRpcClientWebSocket的构造函数,这里假设它部署在同一台机器上:

JsonRpcClient client = new JsonRpcClientWebSocket("ws://localhost:8080/echo");

发送请求

JSON-RPC调用是通过向服务器发送Request对象来表示的。该对象具有以下成员:

  • jsonrpc: 指定JSON-RPC协议版本的字符串,本例中为“2.0”
  • method: 包含要调用的方法的名称的字符串
  • params: 保存在方法调用期间使用的参数值。可以省略此成员,并且该类型由服务器定义
  • id: 客户端标识符。如果请求不包括该值,则假设为通知。如果包含,则服务端将在Response对象中使用相同的值进行应答。此成员用于关联两个对象之间的上下文。

以上这些成员中,用户只需设置“method”和“params”,因为其他两个由底层库管理。

上一节中定义的服务端需要一个JsonObject对象,并且只响应echo方法,返回请求中的“params”。对client.sendRequest(request)响应的***params***被包裹在Response对象中发送回客户端:

Request<JsonObject> request = new Request<>();
request.setMethod("echo");
JsonObject params = new JsonObject();
params.addProperty("some property", "Some Value");
request.setParams(params);
Response<JsonElement> response = client.sendRequest(request);

其他消息:通知

Notification是一个没有“id”成员的Request对象。作为Notfication的Request对象表示客户端对相应的Response对象不感兴趣,因此不需要将Response对象返回给客户端。根据定义,通知是不可确认的,因为它们没有要返回的Response对象。因此,客户端不会发现到任何错误(例如:“无效参数”、“内部错误”):

client.sendNotification("echo");

服务端响应

当服务器接收到RPC调用时,它将回应一个Response,但Notification除外。Response表示为单个JSON对象,成员如下:

  • jsonrpc: 指定JSON-RPC协议版本的字符串,本例中为“2.0”
  • result: 这个成员只有在成功的情况下才会存在。该值由服务器被调用的方法确定
  • error: 此成员仅在调用期间触发错误时存在。类型是一个Error对象
  • id: 这是一个必需的成员,必须与Request中id一致。

Response将有“result”或“error”成员,但两者不能同时存在。

Error对象

当RPC调用遇到错误时,Response对象包含Error成员对象,该成员对象具有以下成员:

  • code: 指示错误类型的数字
  • message: 对错误的简短描述
  • data: 包含错误附加信息的原始值或结构化值。这可以省略,并由服务器定义(例如,详细错误信息、嵌套错误等)。

添加连接监听器

客户端提供了为某些连接事件设置侦听器的功能。用户可以定义一个JsonRpcWSConnectionListener,它提供对某些方法的重写。一旦定义了连接侦听器,就可以传递给客户端的构造函数,一旦产生相应的事件,客户端将调用这些方法:

JsonRpcWSConnectionListener listener = new JsonRpcWSConnectionListener() {

    @Override
    public void reconnected(boolean sameServer) {
        // ...
    }

    @Override
    public void disconnected() {
        // ...
    }

    @Override
    public void connectionFailed() {
        // ...
    }

    @Override
    public void connected() {
        // ...
    }
} ;
JsonRpcClient client = new JsonRpcClientWebSocket("ws://localhost:8080/echo", listener);

管理心跳

正如服务端中所指出的,有一种心跳机制会定期发送ping消息。客户端可以通过以下方法进行控制:

  • enableHeartbeat: 启用心跳机制。默认间隔为5s,但这可以通重载该方法来更改,该方法接收一个数字作为参数。
  • disableHearbeat: 关闭心跳机制

更改默认超时

不仅ping消息的间隔时间是可配置的。其他超时时间也是配置的:

  • 连接超时: 客户端连接服务器时,等待建立连接成功的时间。
  • 空闲超时: 如果在该时间段内没有发送任何消息,则该连接被视为空闲状态并关闭。
  • 请求超时: 服务器应该在一定的时间内响应请求。如果消息在此期间未被应答,则被认为服务器没有收到请求,客户端将产生TransportException。

Java文档

Json-Rpc JS客户端

这是kurento-jsonrpc-server的Javascript客户端,或者任何其他实现JSON-RPC协议的WebSocket服务器。它允许Javascript程序对任何jsonrpc-server进行JSON-RPC调用。被发布为一个浏览器依赖

JsonRpcClient

创建客户端

要创建发送请求的客户端,需要创建一个配置对象,如下所示:

var configuration = {
      hearbeat: 5000,
      sendCloseMessage : false,
      ws : {
        uri : ws_uri,
        useSockJS: false,
        onconnected : connectCallback,
        ondisconnect : disconnectCallback,
        onreconnecting : disconnectCallback,
        onreconnected : connectCallback
      },
      rpc : {
        requestTimeout : 15000,
        treeStopped : treeStopped,
        iceCandidate : remoteOnIceCandidate,
      }
    };

var jsonRpcClientWs = new JsonRpcClient(configuration);

这个配置对象有几个选项:一方面是关于传输的配置,另一方面是关于客户端在获得响应时必须调用的方法的配置。此外,它还可以配置心跳间隔,还可以配置在关闭连接之前是否发送消息。

  • Configuration
{
    heartbeat: interval in ms for each heartbeat message,
    sendCloseMessage: true / false, before closing the connection, it sends a close_session message,
    ws: {
        uri: URItoconntectto,
        useSockJS: true(useSockJS)/false(useWebSocket)bydefault,
        onconnected: callback method to invoke when connection is successful,
        ondisconnect: callback method to invoke when the connection is lost,
        onreconnecting: callback method to invoke when the client is reconnecting,
        onreconnected: callback method to invoke when the client succesfully reconnects
    },
    rpc: {
        requestTimeout: timeoutforarequest,
        sessionStatusChanged: callback method for changes in session status,
        mediaRenegotiation: mediaRenegotiation
        ...
    [Other methods you can add on rpc field are:
treeStopped : treeStopped
   iceCandidate : remoteOnIceCandidate]
    }
}

如果定义了心跳,客户端每隔x毫秒就向服务器发送ping以保持连接。

发送请求

JSON-RPC调用就是通过发送方法发送一个Request对象给服务器。Request对象有以下成员:

  • method: 包含要调用方法名称的字符串。
  • params: 用于保存方法调用时的参数值。可以省略此成员,该类型由服务器定义。是一个json对象。
  • callback: 错误和响应的回调方法。在请求结束时调用此方法。
var params = {
             interval: 5000
              };

jsonrpcClient.send(“ping”, params , function(error, response){
         if(error) {
            ...
         } else {
            ...
         }
      });

服务端响应

当服务器接收到RPC调用时,返回一个Response,Notification除外。Respone表示为JSON对象,成员如下:

  • jsonrpc: 指定JSON-RPC协议版本的字符串,本例中为“2.0”
  • result: 这个成员只有在成功的情况下才会存在。该值由服务器被调用的方法确定
  • error: 此成员仅在调用期间触发错误时存在。类型是一个Error对象
  • id: 这是一个必需的成员,必须与Request中id一

Response包括“result”或“error”成员,但两者不能同时存在。

Error对象

当RPC调用遇到错误时,Response对象包含Error成员对象,该成员对象具有以下成员:

  • code: 指示错误类型的数字
  • message: 对错误的简短描述
  • data: 包含错误附加信息的原始值或结构化值。这可以省略,并由服务器定义(例如,详细错误信息、嵌套错误等)。

其他方法

  • close: 由客户端显式关闭jsonRpcClient。
  • reconnect: 尝试重新连接。
  • forceClose: 它用于测试,强制关闭连接。

WebSocket重连

jsonrpc客户端使用的webSocket具有重连功能,允许连接始终处于活动状态。

当以下任何情况发生时,将触发相应状态对应的回调方法:

  • onConnected
  • onDisconnected
  • onReconnecting
  • onReconnected

下面示例为相关的配置对象,这个对象是jsonrpc客户端的配置对象的一部分:

{
   uri: URItoconntectto,
   useSockJS: true(useSockJS)/false(useWebSocket)bydefault,
   onconnected: callback method to invoke when connection is successful,
   ondisconnect: callback method to invoke when the connection is lost,
   onreconnecting: callback method to invoke when the client is reconnecting,
   onreconnected: callback method to invoke when the client succesfully reconnects
}

JSON-RPC加密连接

从Chrome M47开始,只允许安全源(HTTPS或来自本地主机的HTTP)对getUserMedia进行调用请求。由于Kurento严重依赖JSON-RPC库作为应用的信令部分,因此需要JSON-RPC服务器提供安全的WebSocket连接(WSS),否则客户端将接收mixed content错误,因为不安全的WS连接可能不会通过安全的HTTPS连接进行初始化。

JSON-RPC服务端加密

在Spring中,启用安全的WebSocket连接相当简单。唯一的要求是拥有一个证书,或者是自签名的,或者是由证书颁发机构颁发的。证书必须存储在keystore中,以便以后可以被:term:JVM使用。根据你是否已获得了一个证书或希望生成自己的证书,你将需要执行不同的操作。

  • 证书颁发机构颁发的证书可以通过以下命令导入:
keytool -importcert -file certificate.cer -keystore keystore.jks -alias "Alias"
  • 可以使用以下命令生成保存自签名证书的密钥存储库:
keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048

keystore.jks文件必须放在项目的根路径下,application.properties文件必须放在*src/main/resources/*中,其内容如下:

server.port: 8443
server.ssl.key-store: keystore.jks
server.ssl.key-store-password: yourPassword
server.ssl.keyStoreType: JKS
server.ssl.keyAlias: yourKeyAlias

你可以自定义properties文件存放的位置。当启动基于Spring-Boot的应用时,需要定义一个宏*-Dspring.config.location=&ltpath-to-properties&gt*。更改keystore.jks文件的位置,只需更改键server.ssl.key-store即可。Spring项目的完整正式文档可以在这里找到。

JSON-RPC客户端连接加密服务端

JSON-RPC客户端可以连接到暴露安全连接的服务端。默认情况下,使用的WebSocket库将尝试验证服务端证书。在使用自签名证书的情况下,必须指示客户端跳过此验证步骤。客户端可以通过创建SslContextFactory对象进行设置实现。

SslContextFactory contextFactory = new SslContextFactory();
contextFactory.setValidateCerts(false);

JsonRpcClientWebSocket client = new JsonRpcClientWebSocket(uri, contextFactory);

术语表

这是一个术语词汇表,经常出现在关于多媒体传输的讨论中。大多数术语都被描述并链接到维基百科、RFC或W3C相关文档。有些术语是kurento特有的。

HTTP

超文本传输协议是一种适用于分布式、协同、超媒体信息系统的应用协议。http是万维网数据通信的基础。

另外可以参考:RFC 2616

JAVA

Java是一种通用的计算机编程语言,它是并发的、基于类的、面向对象的,并且专门设计成尽可能少的实现依赖项。

JSON

JSON(JavaScript对象表示法)是一种轻量级的数据交换格式。它被设计成易于为人类理解和编写,也易于对机器进行解析。

JSON-RPC

JSON-RPC是一个简单的用JSON编码的远程过程调用协议。JSON-RPC允许将通知和多个调用发送到服务器,这些调用可能会被无序地响应。

Kurento

Kurento是一个开发多媒体应用程序的平台。Kurento是英语“stream”的世界语。我们之所以选择这个名字,是因为我们相信世界语原则对多媒体社区所需要的东西是鼓舞人心的:简单、开放和普遍性。Kurento是开源的,在Apache2.0下发布,有几个组件,为大多数多媒体公共服务需求提供解决方案。这些组件包括:Kurento Media Server、Kurento API、Kurento Protocol和Kurento Client。

Kurento API

Kurento API是面向对象的API,用于创建控制媒体的媒体管道。它可以看作是Kurento Media Server的接口。它可以在Kurento Protocol或Kurento Client中使用。

Kurento Client

Kurento Client是编程库(Java或JavaScript),在应用中它被用于控制Kurento Media Server。例如,有了这个库,任何开发人员都可以创建一个Web应用程序,该应用程序使用Kurento Media Server从用户Web浏览器接收音频和视频,并将其处理并通过Internet再次发送回来。Kurento Client向应用程序开发人员公开Kurento API。

Kurento Protocol

通过JSON-RPC消息在KMS和客户端之间进行通信。它基于WebSocket,它使用JSON-RPCV2.0消息来发出请求和发送响应。

KMS
Kurento Media Server

Kurento Media Server是Kurento的核心部件,因为它负责媒体的传输、处理、加载和记录。

Maven

Maven是一个主要用于Java项目的构建自动化工具。

Sphinx

用于Brandtalk文档的文档生成系统。

另外可以参考:Easy and beautiful documentation with Sphinx

Spring Boot

Spring Boot是Spring的常规配置解决方案,用于创建独立的、基于产品级的基于Spring的应用程序,你可以“只运行”。[17]它对Spring平台和第三方库采取了自己独特的方式,这样你可以最小配置的情况下使用Spring。

TCP

可靠的IP传输协议。TCP通信确保在传输过程中不会丢失任何数据包。因此,它在低带宽或不可靠的环境中是最有用的。例如慢宽带网络或分组无线网。

UUID

通用唯一标识符,也称为全局唯一标识符(GUID)。在分布式计算环境中,唯一只是尽可能唯一,它不能保证是绝对唯一的,因为标识符集是有限的大小(16个字节)。

WebSocket
WebSockets

WebSocket规范(作为HTML 5计划的一部分开发)定义了一个全双工单套接字连接,通过它可以在客户端和服务器之间发送消息。

WSS
WebSockets Secure

WebSocket规范(作为HTML 5计划的一部分开发)定义了一个全双工单套接字连接,通过它可以在客户端和服务器之间发送消息。

 类似资料: