我正在将分布式系统代码库从SOAP(JAX-WS)迁移到gRPC java。我们使用这个代码库来教授远程调用、容错和安全实现。
在JAX-WS体系结构上,有一个可以拦截SOAP消息的拦截器类(称为SOAP处理程序)。您可以在客户端和服务器上配置处理程序。
作为参考,这是JAX-WS上远程调用的完整序列:
通过这种方法,我们可以创建处理程序来记录SOAP消息,并添加安全性,如数字签名或加密。
我试图在Java(v1.17.2)上与gRPC具有类似的功能。
我基于我的gRPC代码在这个谷歌教程,一个简单的你好世界与一元方法。
基于这些示例,我编写了一个ClientInterceptor:
package example.grpc.client;
import java.util.Set;
import io.grpc.*;
public class HelloClientInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
channel.newCall(methodDescriptor, callOptions)) {
@Override
public void sendMessage(ReqT message) {
System.out.printf("Sending method '%s' message '%s'%n", methodDescriptor.getFullMethodName(),
message.toString());
super.sendMessage(message);
}
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
System.out.println(HelloClientInterceptor.class.getSimpleName());
ClientCall.Listener<RespT> listener = new ForwardingClientCallListener<RespT>() {
@Override
protected Listener<RespT> delegate() {
return responseListener;
}
@Override
public void onMessage(RespT message) {
System.out.printf("Received message '%s'%n", message.toString());
super.onMessage(message);
}
};
super.start(listener, headers);
}
};
}
}
我创建了一个服务器拦截器:
package example.grpc.server;
import java.util.Set;
import io.grpc.*;
public class HelloServerInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata,
ServerCallHandler<ReqT, RespT> serverCallHandler) {
// print class name
System.out.println(HelloServerInterceptor.class.getSimpleName());
return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler);
}
}
以下是(最后)我的问题:
最终的目标是能够编写一个CipherClientHandler和一个CipherServerHandler来加密网络上的消息字节。我知道TLS在实践中是正确的方法,但我希望学生们做一个定制的实现。
感谢任何正确方向的指针!
>
通过"方法执行",我假设您的意思是"服务器执行方法,响应"。调用服务器方法的确切时间不是拦截API的一部分,也不应该依赖于此。对于今天的异步服务器处理程序,当调用serverListener.halfCloch()
时,会调用服务器的方法。但同样,这不应该依赖。不清楚为什么这是必要的。
服务器拦截器接收请求的ReqT消息和响应的RespT消息。要修改消息,只需在调用超级
之前修改这些消息。
客户端拦截器可以做与服务器拦截器相同的事情;在传递消息之前修改消息。
请注意,当我说“修改消息”时,它通常会被实现为“制作一份经过适当修改的消息副本”
但是,如果您想要加密/解密消息,那么从API流出来就不那么容易了,因为您正在完全更改它们的类型。您将获得一个请求
,并将其转换为字节。为此,必须修改MethodDescriptor
s。
在客户端,这可以在start()
中完成,并向MethodDescriptor提供您自己的
。您可以访问应用程序的原始Marshaller
s。生成器MethodDescriptor
,因此可以使用它来序列化为字节。
Marshaller ENCRYPTING_MARSHALLER = new Marshaller<InputStream>() {
@Override
public InputStream parse(InputStream stream) {
return decrypt(stream);
}
@Override
public InputStream stream(InputStream stream) {
return encrypt(stream);
}
};
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
ClientCall<InputStream, InputStream> call = channel.newCall(
methodDescriptor.toBuilder(
ENCRYPTING_MARSHALLER, ENCRYPTING_MARSHALLER),
callOptions);
// Can't use Forwarding* because the generics would break.
// Note that all of this is basically boilerplate; the marshaller is
// doing the work.
return new ClientCall<ReqT, RespT>() {
@Override
public void halfClose() {
call.halfClose();
}
// ... ditto for _all_ the other methods on ClientCall
@Override
public void sendMessage(ReqT message) {
call.sendMessage(methodDescriptor.streamRequest(message));
}
@Override
public void start(Listener<RespT> listener, Metadata headers) {
call.start(new Listener<InputStream>() {
@Override
public void onHalfClose() {
listener.onHalfClose();
}
// ... ditto for _all_ the other methods on Listener
@Override
public void onMessage(InputStream message) {
listener.onMessage(methodDescriptor.parseResponse(message));
}
}, headers);
}
};
}
服务器端通常是相似的,但有点复杂,因为您需要重建ServerService定义
,这不能作为一个普通的拦截器来完成。但是碰巧有一个实用程序可以做样板:
ssd = ServerInterceptors.useMarshalledMessages(ssd, ENCRYPTING_MARSHALLER);
问题内容: 我想在Java-SE应用程序中使用拦截器,并且将weld作为CDI实现,并且在这里进行测试: 主班: 服务等级: 拦截器类: Aaa和输出: 我的问题 第一:为什么我在调用methodCallNumberTwo()时没有在methodCall()中调用拦截器? 第二:有办法改变吗? 我仅研究拦截器的行为,并且想了解。先感谢您! 问题答案: 不会调用拦截器,因为您是在对象的同一实例上调用
我正在开发一个具有多个客户端的标准java RMI服务器。这些客户机有一个菜单,在那里他们可以调用服务器为他们做各种事情。 一种方法涉及一个队列,他们可以在其中将作业发送到队列并等待它得到处理。RMI服务器自动为所有客户端处理线程,但当涉及到此方法和队列时,我如何阻止此请求,例如: 首先调用客户端1,然后再调用客户端2(此处客户端1应首先从服务器接收消息,客户端2应等待服务器处理客户端1请求所需的
我想同步2个集合。如果服务器端有什么变化,连接的客户端就会更新。我有一个非常基本的问题。我现在需要复制我的java项目,并在一个项目中编程服务器,在另一个项目中编程客户端吗?但这听起来像是相当多不必要的工作。我不能在一个项目中实现这一切,然后在一个主项目中启动服务器和客户端吗?我需要线程吗?我有点纠结于最好的方法是什么。提前谢谢。
我想拦截mqtt客户端发送到artemis代理的消息。我遵循的是“拦截器-客户端-MQTT”示例。我的问题是我总是得到一个错误“java.lang.ClassNotFoundException:SimpleMQTTInterceptor”。我的问题是我应该把拦截器类放在哪里,以便代理可以找到它?我应该只放拦截器的类,还是放一个jar文件?
问题内容: 我正在使用RMI编写密码系统的原型。 我有一个问题,因为当我启动两个客户端时,它们从OneTimePad类的服务器中的一个对象获得了响应。 因此客户端A获取为客户端b保留的密钥,由于特定的算法,这种情况不会发生。 服务器仅向客户端发送E和N变量(例如在RSA中),因此我无法序列化OneTimePad对象并通过网络发送它(因为它将具有所有密钥)。 如何为每个客户端创建OneTimePad
我尝试使用Java中的Sockets连接到多个客户端。一切似乎都正常,但问题是,服务器只监听第一个客户端。如果有多个客户端,服务器可以向它们发送所有消息,但他可以只监听来自第一个客户端的消息。我尝试了所有这些(我从昨天开始就遇到了这个问题)。所以我很确定,错误一定在“ClientListener”类中。 说明:有一个客户端列表(用于与字符串通信的连接)。在GUI中有一个列表,我可以在其中选择要与哪