본문 바로가기

Java SE/RMI Callback 01

RMI Callback 01

RMI 를 이용하여 다중이용자 채팅 시스템을 작성해 본다.

클라이언트를 서버에 등록하고 클라이언트가 서버로 메시지를 전송하기 위해 서버측의 broadcast(String msg)를 호출하면 서버측에서는 벡터에 저장된 클라이언트의 참조를 이용하여 getMsg(String msg)를 호출하여 모든 접속자에게 동일한 메시지를 전송해 준다.

서버측 원격인터페이스

import java.rmi.*;

public interface ChatServer extends Remote {

 void registerClient(ClientRemote client)  throws RemoteException;
 void broadcast(String msg) throws RemoteException;
}


서버측 구현크래스

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.*;
import java.util.*;

public class ChatServerImpl extends UnicastRemoteObject implements ChatServer {

 // 클라이언트의 레퍼런스를 저장해 둘 벡터
 private static Vector<ClientRemote> v = new Vector<ClientRemote>();

 public ChatServerImpl() throws RemoteException {}

 public void registerClient(ClientRemote client)  throws RemoteException {
  //client.printDate(new java.util.Date());  //클라이언트측에 있는 콜백메소드를 서버에서 호출

  // 클라이언트 레퍼런스를 벡터에 저장함
  v.add(client);
  System.out.println("인원수:"+v.size());
 }

 public void broadcast(String msg) throws RemoteException {
  for(int i=0;i<v.size();i++) {
   v.get(i).getMsg(msg);
  }
 }
 
 public static void main(String args[]) {
  try {
  ChatServerImpl obj = new ChatServerImpl();

  // 다음 라인을 실행하기 위해서는 rmiregistry.exe 를 먼저 실행해야 한다.
  //Naming.rebind("DateServer", obj);

  // rmiregistry.exe를 직접실행하지 않고 아래처럼 코드상에서 할 수 있다.
  Registry registry = LocateRegistry.createRegistry(1066); // default:1099
  registry.rebind("ChatServer", obj);

  System.out.println("HelloServer bound in registry");

  } catch (Exception e) {

      System.out.println("HelloImpl err: " + e.getMessage());

      e.printStackTrace();

  }
 }
}


클라이언트측 원격인터페이스

import java.rmi.*;

public interface ClientRemote extends Remote {

 // 서버에서 호출가능한 callback메소드 선언
 public void getMsg(String msg)  throws RemoteException;
}



클라이언트측 구현클래스

import java.rmi.*;
import java.rmi.server.*;

public class ChatClient implements ClientRemote {

  // callback 메소드 (서버에서 호출하여 사용가능한 클라이언트 메소드)
 public void getMsg(String msg) {
  System.out.println(msg);
 }

 public static void main(String[] args) {
    try {

  ChatServer obj = (ChatServer)Naming.lookup("rmi://localhost:1066/ChatServer");
  // default(1099)일경우 포트를 명시할 필요없음)

  ChatClient client = new ChatClient();

  //Exports the remote object to make it available to receive incoming calls using an anonymous port.
  // RMI Registry에 바인딩해서 오브젝트를 찾는 방식이 아니라 오브젝트를 서버에 직접 전달하여
  // 메소드호출을 받는 경우이므로 다음과 같이 설정한다
  // 클라이언트 오브젝트를 외부로 내 보기위한 설정
  UnicastRemoteObject.exportObject(client);

  // 클라이언트를 내 보낸다
  obj.registerClient(client);

  obj.broadcast("안녕하세요?");

  System.out.println("클라인트 등록 성공");
    } catch (Exception e) {

      System.out.println(e.getMessage());

      e.printStackTrace();

    }
  }
}