이번시간엔 Reactor에 대해 포스팅해보려고 한다. 앞서 포스팅에서 Protocol을 2개로 만들어서 서버를 만들어 봤었다. 하지만 문제가 되는게 또다른 프로토콜을 추가하게 되면 또 클래스를 정의하고 스위치문에다 포트번호를 넣어주고 일일히 그렇게 다 만들어 줘야한다. 아래와 같은 그림처럼;;
이렇게 해서 어느세월에 프로토콜을 정의 하려 하는지... 그래서 필요한 것이 바로 Reaactor 기능이다.
Reactor의 구조를 대강 살펴보면.... 아래 그림과 같다.
- Reactor Pattern을 사용하여 프로토콜 추가에 유연한 서버를 만든다.
- Map을 이용하여 편하게 클래스 관리를 해본다.
이것이 이번 포스팅의 목표다!! 리엑터기능을 이용한 프로토콜 정의하기!!
만드는 법은 아래와 같다.
1. EventHandler라는 interface를 생성해주고 다음과 같이 코딩한다.
import java.io.InputStream;
public interface EventHandler
{
public String getHandler();
public void handleEvent(InputStream inputStream);
}
2. HandleMap이라는 클래스를 정의해주고 다음과 같이 코딩한다.
import java.util.HashMap;
public class HandleMap extends HashMap<String, EventHandler> ->HandleMap이라고 하는 HashMap을 상속
{
}
3. 기존에 있었던 StreamSayHelloProtocol을 StreamSayHelloEventHandler로 리액터 시켜 이름을 바꿔주고 다음과 같이 코딩해준다.
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
public class StreamSayHelloEventHandler implements EventHandler -> 상속받은것
{
private static final int DATA_SIZE = 512;
private static final int TOKEN_NUM = 2;
@Override
public String getHandler()
{
return "0x5001";
}
public void handleEvent(InputStream inputStream)
{
try
{
byte[] buffer = new byte[DATA_SIZE];
inputStream.read(buffer);
String data = new String(buffer);
String[] params = new String[TOKEN_NUM];
StringTokenizer token = new StringTokenizer(data, "|");
int i = 0;
while(token.hasMoreTokens())
{
params[i] = token.nextToken();
++i;
}
sayHello(params);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void sayHello(String[] params)
{
System.out.println("SayHello -> name: " + params[0] + "age : " + params[1]);
}
}
4. StreamUpdateProfileProtocol도 리액터 시켜 StreamUpdateProfileEventHandler로 이름을 바꿔주고 다음과 같이 코딩해준다.
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
public class StreamUpdateProfileEventHandler implements EventHandler
{
private static final int DATA_SIZE = 1024;
private static final int TOKEN_NUM = 5;
@Override
public String getHandler()
{
return "0x6001";
}
public void handleEvent(InputStream inputStream)
{
try
{
byte[] buffer = new byte[DATA_SIZE];
inputStream.read(buffer);
String data = new String(buffer);
String[] params = new String[TOKEN_NUM];
StringTokenizer token = new StringTokenizer(data, "|");
int i = 0;
while(token.hasMoreTokens())
{
params[i] = token.nextToken();
++i;
}
updateProfile(params);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void updateProfile(String[] params)
{
System.out.println("UpdateProfile ->" +
" id :" + params[0] +
" password : " + params[1] +
" name : " + params[2] +
" age : " + params[3] +
" gender: " + params[4]);
}
}
5. Reactor 클래스를 만들어주고 다음과 같이 코딩해준다.
import java.io.IOException;
import java.net.ServerSocket;
public class Reactor
{
private ServerSocket serverSocket;
private HandleMap handleMap; ->리액터에서 관리할 HandleMap 등록
public Reactor(int port)
{
handleMap = new HandleMap(); ->리액터에서 관리할 HandleMap등록
try
{
serverSocket = new ServerSocket(port);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void startServer()
{
Dispatcher dispatcher = new Dispatcher();
while(true)
{
dispatcher.dispatch(serverSocket, handleMap);
}
}
public void registerHandler(EventHandler handler)
{
handleMap.put(handler.getHandler(), handler); ->핸들러의 헤더등록, 핸들러등록
}
public void removeHandler(EventHandler handler)
{
handleMap.remove(handler.getHandler()); ->핸들러의 헤더등록, 핸들러등록
}
}
6. Serverinitializer로 돌아와 리액터를 등록해 준다.
import java.io.IOException;
import java.net.ServerSocket;
public class Serverinitializer
{
public static void main(String[] args)
{
int port = 5000;
System.out.println("Server ON :" + port);
Reactor reactor = new Reactor(port);
reactor.registerHandler(new StreamSayHelloEventHandler());
reactor.registerHandler(new StreamUpdateProfileEventHandler());
reactor.startServer();
}
}
7. Dispacher 클래스를 만들고 다음과 같이 코딩해준다.
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Dispatcher
{
private final int HEADER_SIZE = 6;
public void dispatch(ServerSocket serverSocket, HandleMap handleMap)
{
try
{
Socket socket = serverSocket.accept();
demultiplex(socket, handleMap);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void demultiplex(Socket socket, HandleMap handleMap)
{
try
{
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[HEADER_SIZE];
inputStream.read(buffer);
String header = new String(buffer);
handleMap.get(header).handleEvent(inputStream);
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
8. 기존에 만들어 놨던 TestClient를 실행해보면....
다음과 같이 그 전에 만들어 놨던 것과 같이 잘 실행된다는 걸 볼 수 있다. 이젠 만들어논 클래스 파일들을 핸들러맵으로 상속시켜서 리액터 시켜놓으면 이상한 번거로움 없이 잘 실행 시킬 수 있다는 것을 보여주고 있다.
'Server > Reactor' 카테고리의 다른 글
Reactor Thread (0) | 2016.08.11 |
---|