U E D R S I H C RSS
ID
Password
Join
ë§Œë¬¼ì˜ ê·¼ì›ì€ 불 - í—¤ë¼í´ë ˆì´í† ìФ(Herakleiros)



Contents

1 시작하며
2 다시 ë©”ì¸ í•¨ìˆ˜
3 Logging_Handler
4 마치며

1 시작하며 #

ì´ íŠœí† ë¦¬ì–¼ì—서는, 우리는 ì²˜ìŒ íŠœí† ë¦¬ì–¼ì—서 ë°°ì› ë˜ ìž‘ì€ ì„œë²„ 하나와 몇가지 추가ì ì¸ ê²ƒë“¤ì„ ë¹Œë“œí•  것ì´ë‹¤. ì´ ê¸€ 마지막ì—는 ë” ê´œì°®ì€ ì„œë²„ ê°ì²´ë¥¼ 만들 것ì´ë‹¤. ì´ê²ƒì€ ë” ë‹¨ìˆœí•˜ê³  ì´ì „ì— ë§Œë“¤ì—ˆë˜ ê²ƒë³´ë‹¤ ë” ê´€ë¦¬í•˜ê¸°ê°€ 쉬운 것ì´ë‹¤.

ì‹œìž‘í•˜ê¸°ì „ì— ìš°ë¦¬ ìžì‹ ì—게 튜토리얼 1ì—서 í–ˆë˜ ì§ˆë¬¸ì„ ë‹¤ì‹œ í•´ë³´ìž :

서버를 ìƒì„±í•˜ëŠ” ë° í•„ìš”í•œ ê²ƒì€ ë¬´ì—‡ì¸ê°€?

  1. í´ë¼ì´ì–¸íŠ¸ë“¤ë¡œë¶€í„° ì ‘ì†ì„ 받아들ì´ëŠ”(accept) ì–´ë–¤ 것
  2. ì„¤ì¹˜ëœ ì ‘ì†ë“¤ì„ 제어하는 ì–´ë–¤ 것
  3. ì´ê²ƒë“¤ 모ë‘를 제어하는 ë©”ì¸ í”„ë¡œê·¸ëž¨ 루프

ì´ì „ì—는, 위 ì§ˆë¬¸ë“¤ì„ ë‚˜íƒ€ë‚´ëŠ” ì†”ë£¨ì…˜ì„ ê°ê° 개별ì ìœ¼ë¡œ 만들었다. 모든 ìž‘ì—…ì´ ë난 후, 어플리케ì´ì…˜ 관련 코드는 í”„ë¡œê·¸ëž¨ì˜ í•¸ë“¤ëŸ¬ë¶€ë¶„ì—ë§Œ 제한ë˜ì–´ìžˆë‹¤ëŠ” ê²ƒì„ ì‹¤ê°í–ˆì„ 것ì´ë‹¤. 여기서, ì´ ì ‘ê·¼ì„ íŒŒí—¤ì³ë³´ìž.

2 다시 ë©”ì¸ í•¨ìˆ˜ #

튜토리얼 1ê³¼ ê°™ì´, ì´ê²ƒ ë˜í•œ ì •ë§ë¡œ ìž‘ì€ í”„ë¡œê·¸ëž¨ì´ë‹¤. 나는 새로운 ì•„ì´ë””어를 ë„ìž…í•´ ë¶™ì¼ ê²ƒì´ì§€ë§Œ ì´ê²ƒì€ ë˜í•œ acceptor를 단순화시키기 위해 치장하는 것ì´ë¼ ìƒê°í•˜ë©´ ëœë‹¤.

Kirthikaì˜ ê°œìš”ëŠ” 다ìŒê³¼ 같다 :

ì´ê²ƒì€ ACEì˜ ì‰½ê²Œ 구할 수 있는 ì»´í¼ë„ŒíŠ¸ì™€ í´ëž˜ìŠ¤ë“¤ì„ ì‚¬ìš©í•¨ìœ¼ë¡œì¨ ë”ìš± 단순하게 만들어진 서버 예제ì´ë‹¤. 여기, Logging_Acceptor는 ACE_SOCK_ACCEPTOR와 Logging_Handler와 ê²°í•©ëœ ACE_Acceptor í´ëž˜ìФì´ë‹¤. ì´ê²ƒì€ ì´ì œ reactor ì¸ìŠ¤í„´ìŠ¤ë¥¼ open시키고 건네받아진 í´ë¼ì´ì–¸íŠ¸ë¡œë¶€í„°ì˜ ì ‘ì†ì„ acceptí•  것ì´ë‹¤. ë˜í•œ ACE_SigAction와 ACE_SignalHandler를 사용해서 CTRL-C를 가로채기 위해서(ì´ê²ƒì€ SIGINT를 ë°œìƒì‹œí‚¨ë‹¤) 시그ë„ì„ êµ¬í˜„í•  것ì´ë‹¤. ì´ ì‹œê·¸ë„ì€ reactorê°€ ì´ë²¤íŠ¸ë¥¼ 다루는 ê²ƒì„ ë©ˆì¶”ê²Œ í•˜ëŠ”ë° ì‚¬ìš©ë  ìˆ˜ 있다.

ì´ì œ, reactor는 CTRL+C를 사용해서 shutdownë  ë•Œê¹Œì§€ 무한 루프를 ëŒì•„ë„ ëœë‹¤. (CTRL+C는 reactor와 acceptor 양쪽다 íŒŒê´´ëœ í›„ì— ë°œìƒí•œë‹¤)

Logging_Handler는 Event_HandlerëŒ€ì‹ ì— ACE_Svc_Handlerì—서 ìƒì†ì„ 받는다. 왜ëƒí•˜ë©´ Svc_Handler는 SOCK_Streamì„ ë‚´ìž¥í•˜ê³  있고 reactorê°€ 요구하는 모든 í˜¸ì¶œì„ ì œê³µí•˜ê¸° 때문ì´ë‹¤. Svc_Handler는 ì´ë²¤íŠ¸ì— ë°˜ì‘í•  수 있는 ëŠ¥ë ¥ì„ ê°€ì§€ê³  있고 숨겨져있는 ë°ì´íƒ€ ìŠ¤íŠ¸ë¦¼ì„ ì‚¬ìš©í•´ì„œ 해당 업무를 조종할 수 있ë„ë¡ í†µì‹ í•  수 있다.

timer는 아무 ê²ƒë„ í•˜ì§€ 않지만 간단하게 주기ì ì¸ 처리가 필요할 때마다 사용ë˜ëŠ” ê²ƒì„ ë³´ì—¬ì£¼ëŠ” reactorì— ì˜í•´ 스케줄ëœë‹¤. ACE_TimeValue는 시간 주기를 설정하는 ë° ì‚¬ìš©ëœë‹¤.

ë˜í•œ, 최ì í™”는 사용한 ê°ì²´ë¥¼ 파괴해주는 별ë„ì˜ í•¨ìˆ˜ì˜ í˜•íƒœë¡œ 만들어져있다.

ë”°ë¼ì„œ "ë”ìš± 간단한" 서버는 ì´ì œ 구축ë˜ì—ˆë‹¤. 어떻게 ìž‘ì—…ì„ ê°„ë‹¨í•˜ê²Œ 하는지를 성공ì ìœ¼ë¡œ 보여주고, 다양한 ACE ì»´í¼ë„ŒíŠ¸ë¥¼ íŒë‹¨ì— 맞게 사용하게 ëœ ì˜ˆë¼ê³  í•  수 있다.

서버 ë©”ì¸ ë¶€ë¶„ 프로그램(server.cpp)ì„ ì°¾ì•„ë³´ëŠ” 것으로 시작해보ìž:

// $Id: ACE_c6_a9_c5_e4_b8_ae_be_f3002_2f_b4_f5_bf_ed_b0_a3_b4_dc_c7_d1_bc_ad_b9_f6,v 1.1 2004/05/20 12:24:46 redpixel Exp redpixel $

/* ì´ì „ì˜ ì˜ˆì²˜ëŸ¼, Logging_Handler를 ì„ ì–¸í•˜ëŠ”ë° ìžˆì–´ 몇가지 ACE
  ê°ì²´ë“¤ì´ 필요하다. */
#include "ace/Acceptor.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/Reactor.h"
#include "handler.h"

/* 우리는 ì•„ì§ ì „ì—­ reactor í¬ì¸í„°ë¥¼ 사용하고 있다. ì´ê²ƒì— 대한 ì¢€ë” í†¡ì˜ëŠ”
   ë°©ë²•ì€ ì°¨í›„ì˜ ì„œë²„ 튜토리얼ì—서 보여주ë„ë¡ í•˜ê² ë‹¤.*/
ACE_Reactor *g_reactor;

/* ì´ê²ƒì€ 튜토리얼 1ì—서 힌트를 주었었다. í•˜ë“œì½”ë”©ëœ acceptor를 우리가 만들었ë˜
  ê²ƒì„ ê¸°ì–µí•˜ëŠ”ê°€? ì´ í…œí”Œë¦¿ 코드는 모든 ì¼ì„ 해주며 ë˜ë ¤ ë” ë§Žì€ ì¼ì„ 한다.
  만약 ì—¬ëŸ¬ë¶„ì˜ ì–´í”Œë¦¬ì¼€ì´ì…˜ì˜ 부분ì´ë¼ê³  ëŠê»´ì§€ì§€ì•ŠëŠ” 코드를 만들고 있다는 것ì„
  깨달았다면, ACEê°€ ì—¬ëŸ¬ë¶„ì„ ìœ„í•´ 그런 ì¼ì„ 해줄 템플릿 ë˜ëŠ” í”„ë ˆìž„ì›Œí¬ ì»´í¼ë„ŒíŠ¸ë¥¼
  가지고 있다는 ê²ƒì€ ì¢‹ì€ ì¼ì¼ 것ì´ë‹¤. */
typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;

/* 새로 ì¶”ê°€ëœ ê²ƒë“¤ì¤‘ 하나는 ì‹œê·¸ë„ í•¸ë“¤ëŸ¬ì´ë‹¤. ì´ê²ƒì€ ê¹”ë”하게 서버가 종료할 수
  있ë„ë¡ í•´ì¤€ë‹¤. "finished" flagì€ ì´ì „ì˜ ë¬´í•œë£¨í”„ ëŒ€ì‹ ì— ì‚¬ìš©ëœë‹¤. 그리고
  "handler"는 SIGINT(CTRL-C)ì— ì‘답하여 ê·¸ flagì„ ì„¤ì •í•œë‹¤. {{{ACE_Reactor::notify()
ì˜
ì‹¤í–‰ì€ handle_events()ê°€ return하는 결과를 만들며, "finished"ë³€ìˆ˜ì˜ ê°’ì´ ë°”ë€ ê²ƒì„ ì•Œìˆ˜ 있게 ëœë‹¤. */
static sig_atomic_t finished = 0; extern "C" void handler (int) {
finished = 1; g_reactor->notify();
}

static const u_short PORT = ACE_DEFAULT_SERVER_PORT;

int main (int, char **) {
// ìƒì†ë°›ì€ ì´ë²¤íЏ 핸들러를 등ë¡í•  reactor를 ìƒì„±í•œë‹¤. ACE_NEW_RETURN (g_reactor, ACE_Reactor, 1);

// í´ë¼ì´ì–¸íЏ ì ‘ì†ì„ listení•  acceptor를 ìƒì„±í•œë‹¤. Logging_Acceptor peer_acceptor;

/* 튜토리얼 1ì˜ open()ì„ í˜¸ì¶œí•œ 것과 비슷하는 ì ì„ 주목하ë¼. ì´ì „ 것ì„
ì½ì–´ë³´ê³  ì´ ë°©ë²•ìœ¼ë¡œ 하기로 했다.(-_-a 번역ì´...ì›ë¬¸ : I read ahead when I created that one so that it would come out this way... */
if (peer_acceptor.open (ACE_INET_Addr (PORT), g_reactor) == -1)
ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);

/* ì—¬ê¸°ì— ì–´í”Œë¦¬ì¼€ì´ì…˜ì— 시그ë„ë“¤ì— ì‘답하는 가장 쉬운 ë°©ë²•ì´ ìžˆë‹¤.
단순히 가로챌 시그ë„ê³¼ "C" 함수를 가지고 ACE_Sig_Actionì„ êµ¬ì¶•í•˜ë©´ ëœë‹¤. 예측했겠지만, reactorì— ì‹œê·¸ë„ í•¸ë“¤ëŸ¬ë¥¼ 등ë¡í•˜ëŠ” ë°©ë²•ë„ ë˜í•œ 존재한다. 하지만 우리는 여기서는 쉬운 방법으로 ê°€ë„ë¡ í•œë‹¤. */
ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);

ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));

// ì‹œê·¸ë„ í•¸ë“¤ëŸ¬ê°€ SIGINT를 ë°›ì„때까지 logging 서비스를 실행한다. while (!finished)
g_reactor->handle_events ();

// acceptor를 ë‹«ì•„ ë”ì´ìƒ í´ë¼ì´ì–¸íŠ¸ë¥¼ 받아들ì´ì§€ 않는다. peer_acceptor.close();

// reactorì— í• ë‹¹ëœ ë©”ëª¨ë¦¬ë¥¼ 해제한다. delete g_reactor;

ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); return 0;
}

#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>; template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> #pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ }}}

3 Logging_Handler #

ì´ì œ 새로운 Logging_Handler를 ë³´ë„ë¡ í•˜ìž:

// $Id: ACE_c6_a9_c5_e4_b8_ae_be_f3002_2f_b4_f5_bf_ed_b0_a3_b4_dc_c7_d1_bc_ad_b9_f6,v 1.1 2004/05/20 12:24:46 redpixel Exp redpixel $

#ifndef LOGGING_HANDLER_H
#define LOGGING_HANDLER_H

#include "ace/INET_Addr.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "ace/SOCK_Stream.h"
#include "ace/Reactor.h"

/* acceptor를 ìƒì„±í•˜ê¸°ìœ„í•´ í…œí”Œë¦¿ì„ ì‚¬ìš©í–ˆê¸° 때문ì—, reactorê°€ ì´ê²ƒì„
  사용하게 하는 ë°©ë²•ì´ ìžˆëŠ”ì§€ 여부를 모른다. 우리는 쉬운 ë°©ë²•ì„ íƒí•˜ë„ë¡
  한다. ì „ì—­ í¬ì¸í„° 변수를 그냥 가져온다. (acceptorì˜ reactor로부터 다시
  얻어오는 ë°©ë²•ì´ ìžˆë‹¤. ë‚˜ì¤‘ì— ì•Œì•„ë³´ë„ë¡ í•œë‹¤.) */
extern ACE_Reactor *g_reactor;

/* ì§€ê¸ˆì€ {{{ACE_Event_Handler}}}ëŒ€ì‹ ì— {{{ACE_Svc_Handler
ì—서 ìƒì†
받기로 한다. ì´ë ‡ê²Œ 하는 í° ì´ìœ ëŠ” ACE_Svc_Handlerê°€ SOCK_Streamì„ í¬í•¨í•˜ëŠ” ë²•ì„ ì•Œê³  있고 reactorê°€ 요구하는 모든 메소드 í˜¸ì¶œì„ ì œê³µí•˜ê¸° 때문ì´ë‹¤. ë‘번째 템플릿 ì¸ìžëŠ” ë‚˜ì¤‘ì— ì œìž‘í•  서버들ì—서 알려줄 약간 어려운 부분ì´ë‹¤. ì§€ê¸ˆì€ ê·¸ëŒ€ë¡œ 가져다 ì“°ë„ë¡ í•œë‹¤. */
class Logging_Handler : public ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH> { public:

/* Acceptor<> í…œí”Œë¦¿ì€ ìƒˆë¡œìš´ í´ë¼ì´ì–¸íЏ ì ‘ì†ì´ ë°œìƒí•  때 open()ì„ ì‹¤í–‰í•œë‹¤. */ virtual int open (void *) {
ACE_INET_Addr addr;

/* ì ‘ì†ë˜ì–´ìžˆëŠ” í´ë¼ì´ì–¸íŠ¸ì˜ ì£¼ì†Œë¥¼ 얻기위해 peer()함수(부모í´ëž˜ìŠ¤ì— ì„ ì–¸ë˜ì–´ìžˆìŒ)
를 호출한다. ì ‘ì†ì´ ëŠì–´ì¡Œì„ 때는 ì´ ë¶€ë¶„ì€ ì‹¤íŒ¨í•˜ë©°, ì•žìœ¼ë¡œì˜ ì‹¤í–‰ì„ ì¤‘ë‹¨í•œë‹¤. */
if (this->peer ().get_remote_addr (addr) == -1)
return -1;

/* Acceptor<>는 ìžì‹ ì˜ reactorì— ìžê¸°ìžì‹ ì„ 스스로 등ë¡í•˜ì§€ 않는다. 그러므로 ì´ê²ƒì€ ì†ìˆ˜
작성해주어야 한다. ì´ê²ƒì´ reactor를 ì „ì—­ í¬ì¸í„°ë¡œ 선언해ë‘어야하는 ì´ìœ ë‹¤. READ_MASK 를 다시 사용하는 ê²ƒì— ì£¼ëª©í•˜ìž. (그러므로 í´ë¼ì´ì–¸íŠ¸ê°€ ì–´ë–¤ ë™ìž‘ì„ í• ë•Œë§ˆë‹¤ handle_input()ê°€ 호출ëœë‹¤.) */
if (g_reactor->register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);

/* ì—¬ê¸°ì— ë˜ë‹¤ë¥¸ 새로운 íŒì´ 있다. 우리는 타ì´ë¨¸ ì´ë²¤íŠ¸ë¥¼ 스케줄한다.
2초가 지나면 ë§Œê¸°ì— ë”°ë¥¸ time-out처리를 하며 다시 매 3ì´ˆí›„ì— ì‹¤í–‰ëœë‹¤. ì´ ì˜ˆì œì•ˆì—서는 ì´ê²ƒì„ 어떻게 사용하는가를 보여주는 ê²ƒì™¸ì˜ ì–´í”Œë¦¬ì¼€ì´ì…˜ 기능ìƒì˜ 다른 ëœ»ì€ ì—†ë‹¤ëŠ” ê²ƒì„ ì•Œì•„ë‘기 바란다. */
else if (g_reactor->schedule_timer (this,
0, ACE_Time_Value (2), ACE_Time_Value (3)) == -1)
ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);

ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ()));

return 0;
}

/* ì´ê²ƒì€ í•˜ë‚˜ì˜ ìŠ¤íƒ€ì¼ì´ê³  ì•„ë§ˆë„ ë§›ë³´ê¸°ë¼ê³  í•  수 있다. 소멸ìžì— ì—¬ê¸°ì— ìžˆëŠ”
모든 ê²ƒë“¤ì„ ë„£ëŠ” 것 대신ì—, ì´ í•¨ìˆ˜ì— ë„£ì–´ë‘ê³  "delete"를 호출하는 모든 ê²½ìš°ì— destroy()를 호출한다. */
virtual void destroy (void) {
/* reactor로 부터 ìžì‹ ì„ 제거한다. */ g_reactor->remove_handler (this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL);

/* 우리가 open()ì—서 스케줄한 타ì´ë¨¸ë¥¼ 취소한다. */ g_reactor->cancel_timer (this);

/* í´ë¼ì´ì–¸íŠ¸ë¡œì˜ ì—°ê²°ì„ ëŠëŠ”ë‹¤. */ this->peer ().close ();

/* ìžê¸°ìžì‹ ì˜ 메모리를 날린다. */ delete this;
}

/* í´ë¼ì´ì–¸íŠ¸ê°€ ì„œë²„ì™€ì˜ ì ‘ì†ì„ ì›í•˜ì§€ 않는다면, ì•„ë§ˆë„ close()를 호출할 것ì´ë‹¤.
실제로, 만약 open()메소드ì—서 -1ì´ ë°˜í™˜ë˜ë©´ Acceptor<>는 뒷처리를 위해서 close()를 실행한다. */
virtual int close (u_long flags = 0) {
/* ACE_Svc_Handler ë² ì´ìФ í´ëž˜ìŠ¤ëŠ” <flags> ì¸ìžë¥¼ 필요로한다. 어쨌거나 우리는 여기서
ê·¸ê²ƒì„ ì‚¬ìš©í•˜ì§„ 않으므로 UNUSED로 설정한다. ì†ŒìŠ¤ì•„ëž˜ì˜ handle_timeout()ì—ì„œë„ ê°™ì€ ê±¸ ë³¼ 수 ìžˆì„ ê²ƒì´ë‹¤. */
ACE_UNUSED_ARG (flags);

/* 제거한 후 사ë¼ì§„다. */ this->destroy (); return 0;
}

protected:

/* 튜토리얼 1ê³¼ ê°™ì´ í´ë¼ì´ì–¸íŠ¸ë¡œë¶€í„°ì˜ ìž…ë ¥ì— ë°˜ì‘하는 함수ì´ë‹¤. */ virtual int handle_input (ACE_HANDLE) {
char buf128; ACE_OS::memset (buf, 0, sizeof (buf));

switch (this->peer().recv (buf, sizeof(buf)))
{ case -1:
ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
case 0:
ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
default:
ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", buf));
}

return 0;
}

/* 타ì´ë¨¸ê°€ 만기ë˜ë©´, handle_timeout()ì´ í˜¸ì¶œëœë‹¤. "arg"는
schedule_timer()í•¨ìˆ˜ì˜ ë‘번째 ì¸ìžë¡œë¶€í„° 넘어오는 ê°’ì´ë‹¤. void * 로 ì„ ì–¸ë˜ì–´ìžˆìœ¼ë¯€ë¡œ ì–´ë–¤ 변수ë¼ë„ ìºìŠ¤íŒ…í•´ì„œ 넘길 수 있다. 여기서는 단순히 메세지만 출력하ë„ë¡ í•œë‹¤. */
virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg) {
ACE_UNUSED_ARG(tv); ACE_UNUSED_ARG(arg); ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this)); return 0;
}

/* handle_input() (ë˜ëŠ” handle_timer())ê°€ -1ì„ ë°˜í™˜í–ˆì„ ê²½ìš° ìžê¸°ìžì‹ ì„ 제거한다. */ virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask) {
this->destroy (); return 0;
}
};

#endif /* LOGGING_HANDLER_H */ }}}

4 마치며 #

ìž, ë‘번째 íŠœí† ë¦¬ì–¼ì´ ë났다. 우리는 서버를 ìƒì„±í•˜ëŠ” ë” ì‰¬ìš´ ë°©ë²•ì„ ì•Œì•„ë³´ì•˜ë‹¤. (특히 accepter부분) ë™ì‹œì—, 함수성과 í™œìš©ì„±ì„ ê°œì„ í•˜ë„ë¡ í•´ë³´ì•˜ë‹¤. í•˜ë£¨ì— í• ìˆ˜ 있는 ì¼ì¹˜ê³ ëŠ” 나ì˜ì§€ 않다. ^^;

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2010-10-28 12:42:52
Processing time 0.4876 sec