Java套接字RPC协议

3
我一直在询问如何调整命令协议以在客户端服务器环境中使用。然而,经过一些实验后,我得出结论:它对我来说行不通。它并没有为这种情况设计。因此,我现在很迷茫。
我以前实现过一种RPC机制,其中有一个名为“Operation”的类。我还有一个名为“Action”的枚举,其中包含可以在服务器上调用的操作名称。
在我的旧项目中,每当客户端想要在服务器上调用操作时,它都会创建'Operation'的实例,并使用“Action”枚举中的值设置动作变量。例如:
Operation serverOpToInvoke = new Operation(); serverOpToInvoke.setAction(Action.CREATE_TIME_TABLE); serverOpToInvoke.setParameters(Map params); ServerReply reply = NetworkManager.sendOperation(serverOpToInvoke);
在服务器端,我必须执行可怕的任务,通过检查'Action'枚举值和一堆'if / else'语句来确定要调用哪个方法。当找到匹配项时,我会调用适当的方法。
这种方法的问题在于它很混乱,难以维护,最终是糟糕的设计。
因此,我的问题是 - 是否有某种模式可以遵循,在Java中通过TCP套接字实现漂亮,清晰和易于维护的RPC机制? RMI对我来说行不通,因为客户端(Android)不支持RMI。我已经耗尽了所有途径。唯一的其他选择可能是REST服务。任何建议都将非常有帮助。
非常感谢 问候
3个回答

8

可能最简单的解决方案是松散地遵循RMI的路径。

你从一个接口和一个实现开始:

interface FooService  {
  Bar doThis( String param );
  String doThat( Bar param );
}

class FooServiceImpl implements FooService {
  ...
}

你需要将接口部署到双方,而实现仅在服务器端部署。为了获取客户端对象,你需要创建一个动态代理。它的调用处理程序除了序列化服务类名、方法名和参数并将其发送到服务器外,不会做任何其他事情(最初可以使用ObjectOutputStream,但是也可以使用其他序列化技术,例如XStream)。服务器监听器接收此请求并使用反射执行它,然后发送响应。实现相当简单,并且对双方都是透明的,唯一的主要问题是你的服务实际上将成为单例。如果需要更多实现细节,请告诉我,但这是我要实施类似解决方案的一般思路。话虽如此,我可能会搜索更多已经存在的解决方案,例如Web服务或类似的东西。更新:这是普通(本地)调用处理程序的工作原理。
class MyHandler implements InvocationHandler {

    private Object serviceObject;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        return method.invoke(serviceObject, args);
    }
}

在这里,serviceObject 是您的服务实现对象被包装成处理程序。

您需要将其分为两部分,而不是调用该方法,您需要将以下内容发送到服务器:

  1. 接口的全名(或其他唯一标识服务接口的值)
  2. 方法的名称。
  3. 方法期望的参数类型的名称。
  4. args 数组。

服务器端需要执行以下操作:

  1. 找到该接口的实现(最简单的方法是使用某种映射,其中键是接口名称,值是实现单例实例)
  2. 使用 Class.getMethod( name, paramTypes ); 找到该方法。
  3. 通过调用 method.invoke(serviceObject, args); 执行该方法并将返回值发送回来。

1
@Joeblackdev 我更新了我的答案,希望能有所帮助。 - biziclop
嗨biziclop - 只是为了澄清:在FooService接口和驻留在服务器上的FooServiceImpl具体类的上下文中。在您上面概述的代理中,serviceObject将如何设置?这将是FooServiceImpl的实例吗?如果是这种情况,我需要在客户端和服务器上都有'FooServiceImpl'类,对吗?再次感谢您的帮助。 - Joeblackdev
1
@Joeblackdev 不,你不会在客户端上实现。示例代码是用于本地代理,演示如何在没有远程部分的情况下执行调用。在远程场景中,您的代理中不会有一个serviceObject,因为您只会将参数发送到服务器并等待响应。在服务器端,您不需要代理,只需要一个监听器,以我描述的方式使用反射执行调用。 - biziclop
嗨,biziclop。我有一个快速问题。如何在客户端创建接口的实例而不实现方法?这就是服务对象的作用吗?非常感谢。 - Joeblackdev
1
@Joeblackdev,这是我为你创建的代码示例,因为我发现我在那个服务对象上犯了一个错误:https://docs.google.com/leaf?id=0B1xDzqs4LVs1NjFmMTNhNDAtMWVhMi00NzFlLThkZWUtYjQ3OWE5ODRjZjkw&hl=en - biziclop
显示剩余2条评论

2
你应该了解一下谷歌的协议缓冲区:http://code.google.com/p/protobuf/。这个库定义了一个IDL,用于生成类似结构体的类,可以从流、字节数组等中进行读写操作。他们还使用定义的消息来定义RPC机制。
我曾经在类似的问题上使用过这个库,效果非常好。

没问题,是的,你用来定义RPC消息的IDL会生成POJO。Java和C++都是目标语言。 - reccles

0

RMI 是正确的选择。

Java RMI 是一种 Java 应用程序编程接口,执行面向对象的远程过程调用(RPC)的等效操作。


嗨,Klark,我这里不能使用RMI。客户端平台(Android)不支持使用RMI。 - Joeblackdev

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