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 

로 입력하면 바로 컴파일 되고 실행파일이 생성됩니다. 





The ADAPTIVE Communication Environment  의 약자가 ACE 이다. 간략하게 기원을 말하면 Douglas C. Schmidts 란 분이 기초를 만들고 Open Source 로 공개를 하자 개발자들이 벌떼처럼 모여들어서 지금의 ACE 를 만들어 냈다.

정식에 가까운 소개를 하자면 ACE 의 Overview 를 번역하는 정도에 그칠듯 하니 일단 ACE 의 공개 홈페이지를 링크하고 (걍 오버뷰를 해석해서 쓸까... )

http://www.cs.wustl.edu/~schmidt/ACE.html


어째서 내가 ACE 를 선택했는지 내 입장에서 글을 쓰는게  여러모로 편리할것 같다. Java 대신 C++ 을 선택한 내 삶에 후회는 없었지만 , 내 입장에서 Java 는 부러운점이 많았다. 그 쉬운 코딩, 강력한 적응성, 쉬운 이식성 - 내가 게으르기 때문에 더더욱 !!

그러다가 맡게 된 KT 전파연구소의 분석서버, 서버는 근 5년간 해 오고 있던 일이라 별로 부담은 없었지만 왜 그리 귀찮았는지.. 다시 소켓 연결하는 부분 Process 나 User 관리하는 부분 , 소켓 관리하는 부분을 다시 항상 하는 모듈과 사용하는 C++ 언어에 연관되게 다시 작성하는 일 ( AIX 면 VAC , 다른 Unix 모듈이면 사용하는 언어가 따로 등등 ) 들을 다시 할려고 생각하니 갑자기 드는 생각이 있었습니다. "아 앞으로도 서버를 만들때마다 이짓을 해야 하나.."

갑자기 드는 생각이 있었습니다. 만약 서버 어플리케이션 종류대로(포크방식이든, 쓰레드 방식이든) 한 모듈을 만들어 놓구, 다른 컴포넌트를 조합해서 서버가 만들어지는 형태로 구현 시켜 놓으면, 나중에 OS 가 바껴도 돌아갈 수 있는 구조가 (흡사 자바처럼) 있다면 그 얼마나 편할까, 한가지 형태만 잘 만들어 두면 조금의 변경만 가해도 그 비싸다는 서버 프로그램을 뚝딱 하고 만들 수가 있지 않을까!! 란 생각에 찾은것이 ACE 입니다.

ACE 는 오픈프로젝트로 전 세계의 잘나가는 사람들이 손을 댔고, 또  전 세계에 자기가 필요로 하는 OS , 개발툴 환경들에 맞게 수정이 가해져서 이식성이 매우 높습니다. 자체적으로도 텍스트가 잘 정의되어 있구, 또 그 텍스트를 바탕으로 해서 나온 책도 여러권 존재합니다. 즉 배우기도 쉽고 - C++ 을 아는 사람이면 누구나 - , 예제도 잘 정리되어 있고, 그 예제에 대한 해석까지 존재하는 정말 속된말로 '괜찮은' 솔루션 입니다. 물론 부정적인 견해의 안티도 존재합니다. 저에게 많은 도움을 주는 Koei 군도 자기말로는 아니라고는 하는데 ACE에 대한 부정적의견을 가끔 내비치고는 합니다.

하지만 개발을 진행해오면서 느꼈던 제 유일의 감정은 말을 하곤 합니다. '여러 사람이 오랬동안 작업과 리팩터링을 해온것은 절대 내가 만든 라이브러리에 떨어질 이유가 없다.' 남들이 뭐라고 해도 이제 귀에 잘 안들어 오는거 같습니다. 쓰면서 진짜 편안함을 느꼈기 때문에, 이게 광신의 지름길이긴 하지만 일단 계속 사용하면서 불편함을 느낄때까지는 써보려고 마음 먹구 진행합니다.

이것은 제 ACE를 쓰면서 시작된 서버프로그래밍의 역사입니다. KT 전파연구소 작업을 할때 진행했던것입니다.

+ Recent posts