2011-02-17 11 views
3

나는 내 클라이언트 서버 환경에서 사용하기 위해 명령 프로토콜을 적용하는 것에 대해 몇 가지 질문을 해왔다. 그러나 몇 가지 실험을 마친 후에는 저에게 효과가 없다고 결론을 내 렸습니다. 이 시나리오에서는 설계되지 않았습니다. 나는 이렇게 느슨한 끝에있다.자바 소켓 RPC 프로토콜

RPC 메커니즘을 구현하기 전에 "Operation"이라는 클래스가있었습니다. 또한 서버에서 호출 할 수있는 작업의 이름이 들어있는 "Action"이라는 제목의 열거 형을 사용했습니다.

이제 내 이전 프로젝트에서 클라이언트가 서버에서 작업을 호출하려고 할 때마다 '작업'인스턴스를 만들고 "동작"열거 형의 값으로 작업 변수를 설정했습니다. 서버 측에 Operation serverOpToInvoke = new Operation();
serverOpToInvoke.setAction(Action.CREATE_TIME_TABLE);
serverOpToInvoke.setParameters(Map params);
ServerReply reply = NetworkManager.sendOperation(serverOpToInvoke);
...

예를

를 들어, 나는 '경우는/다른 진술의 부하와 함께'액션 '열거 값을 검사하여 호출하는 방법을 결정하는 끔찍한 작업을 수행했다. 일치가 발견되면 적절한 방법을 호출합니다.

이 문제는 지저분하고 유지하기가 어려웠으며 궁극적으로 나쁜 디자인이었습니다.

내 질문은 - 내가 자바에서 TCP 소켓을 통해 멋지고 깨끗하고 유지 보수가 잘되는 RPC 메커니즘을 구현할 수있는 패턴이 있습니까? 클라이언트 (안드로이드)가 RMI를 지원하지 않기 때문에 RMI는 나를 위해 아무런 의미가 없습니다. 나는이 단계에서 모든 길을 다 써 버렸다. 다른 옵션은 REST 서비스 일뿐입니다. 조언이 도움이 될 것입니다.

당신에게 감사

답변

8

아마도 가장 쉬운 해결책은 느슨하게 RMI의 경로를 따르는 것입니다.

당신은 인터페이스와 구현으로 시작 :

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

class FooServiceImpl implements FooService { 
    ... 
} 

당신은 양쪽 인터페이스와 서버 측 만에 구현을 배포합니다.

그런 다음 클라이언트 개체를 얻으려면 동적 프록시를 만듭니다. 그것의 호출 핸들러는 아무것도하지 않지만 서비스 클래스 이름, 메소드 이름 및 매개 변수를 직렬화하여 서버에 전송합니다 (처음에는 ObjectOutputStream을 사용할 수 있지만 예를 들어 XStream과 같은 다른 직렬화 기술을 사용할 수 있습니다).

서버 수신기는이 요청을 리플렉션을 사용하여 실행 한 다음 응답을 되돌려 보냅니다.

구현이 매우 쉽고 양면에서 투명합니다. 서비스가 효과적으로 싱글 톤이된다는 유일한주의 사항입니다.

필자는 필요한 경우 구현 세부 사항을 더 포함 할 수 있지만, 이와 같은 것을 구현해야한다면 일반적인 생각입니다.

그런데 아마도 웹 서비스 나 이와 비슷한 비슷한 기존 솔루션을 좀 더 검색 할 것입니다.

업데이트 : 이것은 일반 (로컬) 호출 핸들러가 수행하는 것입니다.

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);를 호출하여 방법을 실행하고 다시 반환 값을 보내 사용 방법을 찾을 수 있습니다.
+0

안녕하세요 biziclop, 리플렉션을 사용하여 명령을 실행하는 서버에 대해 언급 할 때 좀 더 자세히 설명해 주시겠습니까? 당신은 어제 나를 위해 명령 패턴에 대한 게시물에 답변을했고 그 이후로 나는 강력하고 사악한 동적 프록시를 읽었습니다. 나는 코드 감사를 위해 좋다. 나는 전반적인 개념에 더 관심이있다. 많은 도움을 주셔서 감사합니다 – Joeblackdev

+1

@Joeblackdev 내 답변이 업데이트되었습니다. 도움이 되었기를 바랍니다. – biziclop

+0

안녕하세요 biziclop - 그냥 명확히하기 : 서버에 상주하는 FooService 인터페이스 및 FooServiceImpl 구상 클래스의 컨텍스트에서. 위에서 요약 한 프록시에서 serviceObject는 어떻게 설정됩니까? 이것이 FooServiceImpl의 인스턴스입니까? 이 경우 클라이언트와 서버 모두에서 'FooServiceImpl'클래스가 필요합니다. 맞습니까? 귀하의 도움에 다시 한 번 많은 감사를드립니다. – Joeblackdev

0

RMI이 길을 가야하는 것입니다 대단히 감사합니다.

자바 RMI는 원격 프로 시저 호출 (RPC)의 객체 지향 당량을 수행하는 자바 애플리케이션 프로그래밍 인터페이스 이다.

+0

안녕하세요. Klark, 여기서는 RMI를 사용할 수 없습니다. 클라이언트 플랫폼 (Android)은 RMI의 사용을 용이하게하지 않습니다. – Joeblackdev

2

당신은 구글에서 프로토콜 버퍼로 보일 것입니다 : http://code.google.com/p/protobuf/

이 라이브러리는 등 스트림/바이트 배열 /에서 읽고 쓸 수있는 클래스와 같은 구조체를 생성하는 IDL을 정의합니다. 또한 정의 된 메시지를 사용하여 RPC 메커니즘을 정의합니다.

나는이 라이브러리를 비슷한 문제에 사용했고 아주 잘 작동했다.

+0

안녕하세요. 답장을 보내 주셔서 감사합니다. Android에서이 기능을 사용할 수 있습니까? – Joeblackdev

+0

문제는 없지만 RPC 메시지를 정의 할 때 사용하는 IDL은 POJO를 생성합니다. Java와 C++ 모두 대상 언어입니다. – reccles