메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

모바일 P2P 메시징, Part 2: 일반적인 P2P 네트워크로 모바일 확장 개발하기 (한글)

모바일 디바이스를 JXTA와 Jabber 클라이언트로 전환하기

Michael Juntao Yuan, 전자상거래 센터, 연구원, University of Texas at Austin
Michael J. Yuan: 연구원(University of Texas at Austin, 전자상거래센터).

요약:  JXTA와 Jabber 같은 일반적인 P2P 컴퓨팅 네트워크는 모바일 디바이스에 적용하기에는 너무 복잡하다. 따라서 경량 모바일 클라이언트나 릴레이(relay)를 통해 작동하는 특별한 아키텍쳐는 P2P 커뮤니티를 모바일 사용자로 확대되어야 한다. Michael Yuan은 J2ME JXTA 클라이언트 프로젝트인 JXME를 설명한다.

원문 게재일:  2004 년 3 월 10 일 (출판일: 2003 년 1 월 01 일)
난이도:  초급
페이지뷰:  981 회
의견:  


SMS 기반 메시징은 무선 전화 사용자들에게는 매우 편리하다. 하지만, PDA와 WAN 연결 핸드헬드 같은 모바일 장치에는 합당한 메시징 플랫폼이 아니다. 다양한 셀 네트워크(국제 전화)를 통한 SMS 메시징 역시 값이 비싸거나 어떤 경우는 불가능하다. 이 글에서는 두 개의 범용 P2P 네트워크인 JXTA P2P와 Jabber 인스턴트 메시징 네트워크를 소개하겠다.

JXTA 프레임웍

JXTA는 P2P 네트워크용 오픈 프로토콜을 정의한다. 이 XML 기반의 프로토콜은 피어 디스커버리, 엔드포인트 라우팅, 커넥션 바인딩, 기본 쿼리/응답 메시지 교환, 랑데부 피어를 통한 네트워크 파급 같은 복잡한 작동을 정의한다. JXTA 네트워크는 다음과 같은 컴포넌트로 구성되어 있다:

  • 피어(peer)는 JXTA 네트워크의 기본적인 엘리먼트이다. 피어는 핵심 JXTA 프로토콜을 구현하고 모든 다른 피어들과 독립적이고 비동기식으로 작동한다. 피어는 애플리케이션과 네트워크 서비스를 제공하고 피어 자체를 광고할 수 있다.
  • 피어 그룹은 피어들의 모음이다. JXTA는 그룹을 만들고 참여하고 감시하기 위해 피어들이 사용하는 프로토콜을 정의한다. 그룹은 피어 발견, 멤버쉽, 액세스 제어, 파이프, 클라이언트(resolver), 모니터링 같은 서비스를 제공한다.
  • 파이프(Pipe)는 피어들 간 가상 연결을 나타낸다. point-to-point 파이프는 두 개의 피어를 연결한다. propagate 파이프는 방송 피어를 다중 리스너에 연결한다. 파이프가 연결된 피어들은 직접 물리적 링크가 될 필요는 없다. 여러 개의 중간 파이프를 통해 연결될 수 있기 때문이다.
  • 메시지(Message)는 피어들과 엔드포인트 간, 파이프를 통해 교환되는 데이터이다. JXTA는 모든 메시지용 envelope 포맷을 정의한다. 각 피어는 자신의 메시지 컨텐트 포맷을 정의할 수 있다. 단 포맷은 XML 스팩에 호환되어야 한다. 하지만 두 개의 피어들이 정보를 교환하기 위해서는 상대방의 메시지 포맷을 이해해야 한다.
  • 광고(Advertisement)는 JXTA 네트워크 리소스를 기술하기 위한 메타데이터 구조이다. 모든 피어들과 서비스들은 광고를 이해한다.

JXTA는 단순한 메시지교환 이상의 P2P 프레임웍이다. P2P 파일 공유, P2P 애플리케이션 서비스, 협업 분산 컴퓨팅 같은 문제를 다루고있다. JXTA 프로토콜은 모든 구현 기술에 독립적으로 설계된 반면 JXTA의 레퍼런스 구현은 자바 플랫폼에 구현된다. 이 레퍼런스 구현은 자바 API를 사용하여 JXTA 프로토콜 메시지를 래핑하고 프로그램 방법으로 자바 애플리케이션에서 JXTA 네트워크에 액세스한다.


모바일 장치용 JXTA

JXTA의 힘과 유연성은 복잡성이라는 상당한 대가를 치르고 얻어졌다. JXTA 피어는 많은 태스크를 관리하고 XML-소켓 레벨에서 메시지를 처리한다. 그와 같은 피어는 너무나 복잡해서 대부분의 모바일 디바이스 상에서는 실행할 수 없다. 게다가, XML이나 원래의 소켓 지원은 표준 J2ME/MIDP 스팩의 일부이다. 모바일 P2P 사용자들에게 JXTA 네트워크를 가능하게 하려면 모바일 디바이스용 JXTA API가 필요하다. JXME 프로젝트는 JXTA API를 CLDC와 MIDP 플랫폼에 제공하는 것을 목표로하고 있다. 이것은 Personal Profile 같은 J2ME 프로파일에도 사용된다.

JXME은 릴레이(relay)를 사용하여 경량의 모바일 피어들을 나머지 JXTA 네트워크에 연결한다. 릴레이 자체로는 랑데부 JXTA 피어로서 파이프, 광고, 피어 그룹 서비스를 핸들할 수 있다. 모바일 피어는 HTTP를 통한 바이너리 연결을 통해 릴레이들과 통신한다. 이때 JXTA Binary Message 포맷에 순응하는 메시지를 사용한다. 릴레이는 모바일 피어들에게 많은 피어 서비스를 제공한다:

  • 릴레이는 불필요한 광고를 걸러내고 그런 광고들을 없애 대역폭을 저장한다.
  • 릴레이는 메시지들을 모바일 피어들에 라우팅한다.
  • 릴레이는 JXTA XML 포맷에서 JXTA Binary Message 포맷으로 메시지들을 변환한다. 그 반대도 수행한다. 모바일 피어와 일상 피어들 간 상호운용성을 위해서이다.
  • 릴레이는 모바일 피어를 대신하여 프록시로서 작동한다. 릴레이는 다른 피어와 파이프와 인터랙팅하고 그룹 서비스를 사용한다.

JXME API

JXME 패키지를 다운로드하면 데모를 실행할 수 있다. 다운로드 패키지에 포함된 Ant 구현 스크립트를 사용하여 단계별로 데모를 실행한다. 자세한 튜토리얼은 JXME 웹 사이트를 참조한다.

우선, 모바일 디바이스와 목표 JXTA 커뮤니티에서 접근 가능한 컴퓨터에 릴레이 피어를 실행해야 한다. proxy 디렉토리의 build.xml 파일에는 runproxy 태스크가 포함되어 있어 JXME을 릴레이를 실행한다. 적당한 박스를 점검하여 Rendevous, relay, JxtaProxy 로서 실행한다. 이제 JXME 피어를 실행할 수 있다. 다운로드 패키지에는 두개의 샘플 JXME 애플리케이션(chat & tictactoe)이 포함되어 있다.

JXME 패키지를 보자. JXME API는 세 개의 클래스를 가지고 있으며 모두 net.jxta.j2me 패키지에 있다:

  • Element는 JXTA 메시지 내의 엘리먼트이다. 엘리먼트에는 네임, 네임스페이스, MIME 타입, 데이터의 바이너리 어레이가 포함되어 있다.
  • Message는 여러 개의 엘리먼트로 구성된 JXTA 메시지이다. Message는 그러한 엘리먼트에 액세스하기 위해 메소드를 제공한다.
  • PeerNetwork는 가장 유용한 클래스이다. JXTA 태스크를 설정하여 모바일 피어가 릴레이를 통해 수행될 수 있게 한다. 다음은 PeerNetwork 클래스의 유용한 메소드들이다:

    • createInstance()는 지정된 피어 이름을 가진 PeerNetwork의 인스턴스를 리턴하는 팩토리 메소드이다.
    • connect() 메소드는 지정된 HTTP URL에서 릴레이로 연결한다. 영속 상태 정보의 바이트 어레이를 리턴한다.
    • create() 메소드는 릴레이 프록시를 통해 JXTA 네트워크 상에 피어, 그룹, 파이프를 만든다.
    • search() 메소드는 피어, 그룹, 파이프를 검색한다.
    • poll() 메소드는 이 모바일 피어에 접근하는 메시지용 모든 릴레이들을 등록한다. 서버 쓰레드에서 반복적으로 호출 될 수 있다.
    • listen()close() 메소드는 인풋 파이프를 열고 닫는다.
    • send() 메소드는 메시지를 지정된 파이프에 보낸다.

예제

JXME 웹 사이트의 JXME 소스 코드 패키지에 포함된 mySend.java 튜토리얼 예제를 사용하여 앞서 설명한 API 사용법을 설명하겠다. JXME 패키지는 Project JXTA에 대한 개별적 기여들로 이루어져 있다. 소스 코드는 Sun Project JXTA Software License의 허가를 받았다.

J2ME 에뮬레이터에서 실행되는 예제 모바일 피어는 9700 포트의 호스트 PC(localhost) 상에서 실행되는 JXME 릴레이를 통해 많은 액션들을 수행한다. 물론 실제 전개시에는 모바일 피어는 모바일 디바이스상에서 실행될 수 있으며 localhost를 자신의 릴레이 컴퓨터의 IP 어드레스로 바꿀 수 있다. JXME 릴레이는 다운로드 패키지에 포함되어 있다.

예제 피어는 다음 단계를 거친다:

  1. 새로운 파이프를 만든다.
  2. 설치된 파이프를 찾는다.
  3. 그 파이프를 통해 메시지를 보낸다.
  4. 메시지를 받는다.

Listing 1은 peer.listen() 메소드가 릴레이에게 새로운 파이프를 만들것을 명령하고 있다.


Listing 1. 새로운 파이프 구현하기
// Create a peer and have it connect to the relay.
// A connection to relay is required before any other
// operations can be invoked.
String relayUrl = "http://localhost:9700/";
PeerNetwork peer = PeerNetwork.createInstance("mySendPeer");
byte [] persistentState = peer.connect(relayUrl, null);
 
// Have the peer create and open a Unicast pipe; PipeID will
// be returned asynchronously in a response message
int listenQueryId = peer.listen("myPipe", null, PeerNetwork.UNICAST_PIPE);
 
// Have peer search for this Pipe and then send it a Message
String pipeID = findMyPipe();
sendMyMessage(pipeID);
 
// Finally, have the peer poll for Messages sent to it
recvMessage();
}

파이프 만들기가 성공하면 릴레이는 바이너리 메시지를 모바일 피어에 만든다. findMyPipe() 메소드는 성공을 나타내는 메시지를 받을 때 까지 루프 안에서 릴레이를 등록한다. 그런 다음 메시지를 파싱하고 파이프 ID를 얻는다. 바이너리 메시지는 XML 같은 구조를 갖고있다. (Listing 2).


Listing 2. Getting the pipe we just created
public String findMyPipe() throws IOException {
  // Now poll for all messages addressed to us. Stop when we
  // find the response to our listen command
  int rid = -1;
  String id = null;
  String type = null;
  String name = null;
  String arg = null;
  String response = null;
 
  Message msg = null;
  while (true) {
    // do not use a timeout of 0, 0 means block forever
    msg = peer.poll(1);
    if (msg == null) {
      continue;
    }
    // look for a response to our search query
    for (int i = 0; i < msg.getElementCount(); i++ ) {
      Element e = msg.getElement(i);
      if (Message.PROXY_NAME_SPACE.equals(e.getNameSpace())) {
        String elementName = e.getName();
        if (Message.REQUESTID_TAG.equals(elementName)) {
          String rids = new String(e.getData());
          try {
            rid = Integer.parseInt(rids);
          } catch (NumberFormatException nfx) {
            System.err.println("Recvd invalid " +
                               Message.REQUESTID_TAG +
                               ": " + rids);
            continue;
          }
        } else if (Message.TYPE_TAG.equals(elementName)) {
          type = new String(e.getData());
        } else if (Message.NAME_TAG.equals(elementName)) {
          name = new String(e.getData());
        } else if (Message.ARG_TAG.equals(elementName)) {
          arg = new String(e.getData());
        } else if (Message.ID_TAG.equals(elementName)) {
          id = new String(e.getData());
        } else if (Message.RESPONSE_TAG.equals(elementName)) {
          response = new String(e.getData());
        }
      }
    }
    // PIPE_NAME: myPipe
    // PIPE_TYPE: PeerNetwork.UNICAST_PIPE
    if (rid == listenQueryId &&
        response.equals("success") &&
        type.equals("PIPE") &&
        name.equals(PIPE_NAME) &&
        arg.equals(PIPE_TYPE)) {
      return id;
    }
  }
}

sendMyMessage() 메소드는 findMyPipe() 메소드에서 리턴된 파이프 ID를 갖고 파이프를 통해 메시지를 보낸다. (Listing 3).


Listing 3. 파이프를 통해 메시지 보내기
public void sendMyMessage(String pipeID)
    throws IOException {
  Element[] elm = new Element[2];
  // Our Message will contain two elements. Receiver should look for
  // elements with the same names ("mySend:Name" and "mySend:Message")
  // PEER_NAME: mySendPeer
  elm[0] = new Element("mySend:Name", PEER_NAME.getBytes(),
                       null, null);
  elm[1] = new Element("mySend:Message", "Hello there".getBytes(),
                       null, null);
  Message msg = new Message(elm);
  // PIPE_NAME: myPipe
  // PIPE_TYPE: PeerNetwork.UNICAST_PIPE
  sendRequestId = peer.send(PIPE_NAME, pipeID, PIPE_TYPE, msg);
  System.out.println("send request id: " + sendRequestId);
}

mySendPeer는 파이프를 리스닝하고 있다. 따라서 우리가 보낸 메시지는 릴레이에서 온 같은 모바일에 사용할 수 있다. recvMessage() 메소드는 이 메시지를 받을 때 까지 릴레이를 등록하고 받으면 이 메시지를 디스플레이한다. (Listing 4).


Listing 4. 메시지 받기
public void recvMessage() throws IOException {
  Message msg = null;
  while (true) {
    msg = peer.poll(1);
    if (msg == null) {
      continue;
    }
    for (int i = 0; i < msg.getElementCount(); i++) {
      Element e = msg.getElement(i);
      if ("mySend".equals(e.getNameSpace()) &&
          "Name".equals(e.getName()))
        System.out.println("Message from: " +
                           new String(e.getData()));
      if ("mySend".equals(e.getNameSpace()) &&
          "Message".equals(e.getName()))
        System.out.println("Message: " +
                           new String(e.getData()));
    }
  }
}


Jabber 인스턴트 메신저

P2P 시스템의 성공은 사용자를 끌어들이는 능력에 달려있다. JXTA가 매우 강력하고 기술적으로도 앞선 프레임웍이지만 복잡성 때문에 채택을 망설이고 있다. Jabber는 JXTA 보다 훨씬 단순한 P2P 시스템이다. 주로 인스턴트 메시지 교환용으로 설계되었다. Jabber는 JXTA 보다 넓은 피어 네트워크를 갖고 있다.

Jabber는 원래 대중적인 인터넷 인스턴트 메시징 시스템(AOL, MSN, Yahoo!, ICQ)간 상호 운용성을 제공할 목적으로 설계되었다. 모든 기존의 IM 프로토콜을 래핑할 수 있는 강력하고 유연하면서도 단순한 프로토콜이다. 강력한 기능과 완전히 개방된 XML 프로토콜이라는 점 외에도 Jabber는 가장 진보된 IM 시스템이다. Jabber는 고급 P2P 애플리케이션을 지원한다.

Jabber 피어들은 Jabber 서버들을 통해 서로 서로 통신한다. Jabber 서버는 상호 통신하여 피어들의 큰 도메인을 형성한다. 이것은 같은 서버로는 직접 연결되지 않는다. Jabber 피어와 서버 간 모든 통신은 개방 XML 포맷의 메시지 형태를 취한다. 결과적으로 Jabber 서버와 피어는 플랫폼과는 독립적으로 구현된다. Jabber 개발 라이브러리는 자바, C++, C#, Perl, Python, PHP, Flash에서도 가능하다.

J2ME 디바이스(특히, MIDP 디바이스)용 Jabber 클라이언트 개발은 쉬운일이 아니다. 모든 MIDP Jabber 클라이언트는 XML 파서가 있어야한다. 게다가 MIDP VM과 기저 네트워크가 원시 소켓 연결을 지원해야 한다. MIDP 1.0 호환의 Jabber 클라이언트 또는 라이브러리가 많이 있다:

  • Al Sutton의 KVMJab은 MIDP 플랫폼을 위한 오픈 소스 Jabber 라이브러리이다. MIDP Jabber 애플리케이션 개발에 필요한 간단한 API를 제공한다.
  • uppli의 uMessenger는 완벽한 기능의 Jabber IM 클라이언트 이다. 파일 공유를 지원한다.

참고자료

필자소개

Michael J. Yuan: 연구원(University of Texas at Austin, 전자상거래센터).

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=자바
ArticleID=18277
ArticleTitle=모바일 P2P 메시징, Part 2: 일반적인 P2P 네트워크로 모바일 확장 개발하기 (한글)
publish-date=03102004
author1-email=
author1-email-cc=

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.