Notice
Recent Posts
Recent Comments
Dharma
ACE 기반의 에코서버(Echo Server) 우분투 환경에서 만들기 본문
ACE 는 훌륭한 네트워크 프레임 워크 입니다. 서버를 작성할 때 신경써야 할 귀찮은 것들을 알아서 처리를 해줍니다. 그러한 ACE를 이용해서 우분투에서 간단한 에코서버(Echo Server)를 작성하는 방법을 알아보겠습니다.
1. 설치
그 귀찮은 ACE 받고 , 압축 풀고, 컴파일 하는 과정이 우분투에서는 간단한 명령 몇번이면 다 됩니다.
sudo apt-get install libace-5.6.3 libace-dev libace-doc mpc-ace
각각의 설명입니다.
i libace-5.6.3 - C++ network programming framework
i libace-dev - C++ network programming framework develop
i libace-doc - C++ network programming framework document
i mpc-ace - makefile, project and workspace creator
libace* 들은 ACE 관련 라이브러리와 헤더들입니다. mpc-ace 는 편하게 ACE 관련한 프로젝트 make 해주는 관리 툴입니다. (진짜 편합니다. 예전에 직접 작성해줄려고 하면 여러가지로 귀찮았습니다)
2. 환경 설정
.bashrc 에
export ACE_ROOT=/usr/share/ace
export LD_LIBRARY_PATH=/usr/lib:$ACE_ROOT/lib:$LD_LIBRARY_PATH
라고 추가 설정해 주고
source ~/.bashrc
라고 입력해줍니다.
3. 에코 서버 (Echo Server)
메아리 서버라고도 부르지요, 뭔가를 입력하면 똑같은 말을 돌려주는 기능을 가진 서버로 거의 모든 서버의 기본입니다. (서버 세계의 Hello World 라고나 할까요?)
이 소스는 어디선가 봐서 따온 것인데요. 누구것인지 기억이 안납니다. 혹시나 이 게시물을 보시게 되면 연락주세요 (__
9088 포트에 에코서버를 띄우고 클라이언트의 접속을 기다립니다.
#include <ace/OS.h> #include <ace/Log_Msg.h> #include <ace/Message_Block.h> #include <ace/INET_Addr.h> #include <ace/Svc_Handler.h> #include <ace/SOCK_Acceptor.h> #include <ace/SOCK_Stream.h> #include <ace/Synch_Traits.h> #include <ace/Reactor.h> #include <ace/Acceptor.h> #include <ace/Reactor_Notification_Strategy.h> class Stream_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> { private : typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super; ACE_INET_Addr remote_addr_; ACE_Reactor_Notification_Strategy noti_; public : Stream_Handler() : noti_(0, this, ACE_Event_Handler::WRITE_MASK) { /* empty */ } //override virtual int open(void * = 0) { ACE_TRACE("Stream_Handler::open"); if( super::open() == -1 ) return -1; noti_.reactor(this->reactor()); this->msg_queue()->notification_strategy(¬i_); if( this->peer().get_remote_addr(remote_addr_) == 0 ) { ACE_DEBUG((LM_INFO, "[DEBUG%T](%N:%l) ### New client accepted: %s:%u\n", remote_addr_.get_host_addr(), remote_addr_.get_port_number())); } return 0; } //override virtual int handle_input(ACE_HANDLE handle = ACE_INVALID_HANDLE) { ACE_TRACE("Stream_Handler::override"); char buf[1024]; ssize_t recv_cnt; if( (recv_cnt = this->peer().recv(buf, 1024)) <= 0 ) return -1; ACE_Message_Block *mb; ACE_NEW_RETURN(mb, ACE_Message_Block(buf, recv_cnt), -1); mb->wr_ptr(recv_cnt); this->putq(mb); return 0; } //override virtual int handle_output(ACE_HANDLE handle = ACE_INVALID_HANDLE) { ACE_TRACE("Stream_Handler::handle_output"); ACE_Message_Block *mb; ACE_Time_Value nowait(ACE_OS::gettimeofday()); while( this->getq(mb, &nowait) != -1 ) { ssize_t send_cnt = this->peer().send(mb->rd_ptr(), mb->length()); if( send_cnt == -1 ) ACE_ERROR((LM_ERROR, "[ERROR%T](%N:%l) ### %p\n", "Stream_Handler::handle_output")); else mb->rd_ptr(send_cnt); if( mb->length() > 0 ) { this->ungetq(mb); break; } mb->release(); } if( this->msg_queue()->is_empty() ) this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK); else this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK); return 0; } //override virtual int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask) { ACE_TRACE("Stream_Handler::handle_close"); ACE_DEBUG((LM_INFO, "[DEBUG%T](%N:%l) ### Connection close %s:%u\n", remote_addr_.get_host_addr(), remote_addr_.get_port_number())); return super::handle_close(handle, close_mask); } }; int ACE_TMAIN(int argc, ACE_TCHAR *argv[]) { ACE_INET_Addr listen; listen.set(9088); ACE_Acceptor<Stream_Handler, ACE_SOCK_ACCEPTOR> acceptor; acceptor.open(listen); ACE_Reactor::instance()->run_reactor_event_loop(); ACE_RETURN(0); }
또한 이 소스는 Reactor 를 쓰고 있는데 그것에 관한 설명은 다음으로 미루기로 하지요. 설명하자면 끝도 없을 테니까요. 위 내용을 server.cpp 로 저장합니다.
4. mpc-ace
mpc 는 복잡하게 작성해야만 했던 ACE 관련한 makefile 을 정말 편하게 만들어 주는 관리 툴입니다. 기본적으로 확장자가 mpc 인 파일이 필요합니다.
server.mpc
project(server) : aceexe {
exename = server
// includes += directory_name other_directory
// libpaths += /usr/X11R6/lib
Header_Files {
}
Source_Files {
server.cpp
}
}
project(server) 를 보면 ( ) 안의 이름으로 make 파일이 만들어 집니다.
aceexe 라고 쓰여진 것은 ace 관련된 실행파일로 만들라는 이야깁니다.
exename = server 는 server 라는 이름의 실행파일이 만들어 집니다.
includes 와 libpaths 는 추가되는 참조 디렉토리와 라이브러리를 더할 때 쓰입니다. 여기서는 안 쓰니 코멘트 처리합니다.
Source_Files 에 컴파일할 대상을 적어줍니다. 현재 server.cpp 밖에 없습니다.
mpc-ace server.mpc -type gnuace
로 입력하면 GNUMakefile.server 라고 메이크파일이 하나 생성됩니다.
make -f GNUMakefile.server
로 입력하면 바로 컴파일 되고 실행파일이 생성됩니다.