블로그 이미지
fiadot_old

칼퇴근을 위한 게임 서버 개발 방법론에 대한 심도있는 고찰 및 성찰을 위한 블로그!

Rss feed Tistory
Technical Article 2013. 1. 27. 00:34

cpp-netlib 0.9.4 visual studio 2010 사용해보자!

왜???

클라우드, 스마트폰 => HTTP 서버, 클라이언트

결국 스케일 아웃을 위해서 Restful 방식으로 될 수 밖에!

 

- MS casandra

native C++ 을 위한 MS의 restful 지원책 => 실제로는 azure에 끌어들이기 위한것 아닌가?

공식 사이트에서도 설명했지만 production 레벨로 권고하지 않음. 아직 개발단계이니...

성능 테스트 해봤을 때 좀 실망적...

 

- Boost ASIO + custom HTTP

간단하게 짜기 좋으며 성능도 짱.

 

- Boost cpp-netlib

아직 정식 boost 배포에 포함되지는 않았지만 노력중인듯.

HTTP, URI, header 등... 필요한 건 다 있는듯

 

 

 

cpp-netlib 0.9.4 빌드 방법

 

1. Jamroot파일에서 주석처리

#build-project libs/network/test ;
#build-project libs/mime/test ;

 

2. libs/network/build/Jamfile.v2 에서 from -> to 로 변경

from: lib cppnetlib-uri : libs/network/src/uri/parse.cpp ;
to: lib cppnetlib-uri : libs/network/src/uri/uri.cpp libs/network/src/uri/schemes.cpp ;

3. boost 폴더에서 bjam 복사

 

4. 실행

cd cpp-netlib-0.9.4

 

bjam.exe -sBOOST_ROOT=C:\Dev\boost_1_52_0 toolset=msvc address-model=32 variant=debug link=static
bjam.exe -sBOOST_ROOT=C:\Dev\boost_1_52_0 toolset=msvc address-model=32 variant=release link=static
bjam.exe -sBOOST_ROOT=C:\Dev\boost_1_52_0 toolset=msvc address-model=64 variant=debug link=static
bjam.exe -sBOOST_ROOT=C:\Dev\boost_1_52_0 toolset=msvc address-model=64 variant=release link=static

 

5. 빌드 후 라이브러리 파일 경로

cpp-netlib-0.9.4\libs\network\build\bin

 

* 파일명이 빌드타입이나 비트에 따라 별도로 생성 안 됨 ㅡㅡ;

 

 

참조  : https://groups.google.com/forum/?fromgroups#!topic/cpp-netlib/HCahOzmLe54

 

 

 

샘플 테스트

 

 

서버> node.js

var cluster = require('cluster');

var numCPUs = require('os').cpus().length;
// var numCPUs = 1;

if ( cluster.isMaster )
{   
 for (var i = 0; i < numCPUs; i++) {
  cluster.fork();  
 }   
 
 cluster.on('death', function(worker)  {   
  logger.info('worker ' + worker.pid + ' died & restart');
  cluster.fork();                   
 }); 
}
else
{
 var sys = require("sys"),
 my_http = require("http");
 my_http.createServer(function(request,response){ 
  response.writeHeader(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
 }).listen(80);
 sys.puts("Server Running on 80"); 
}

 

 

샘플>
#include <boost/network/protocol/http/client.hpp>
#include <iostream>

#pragma comment(lib, "libcppnetlib-client-connections.lib")
#pragma comment(lib, "libcppnetlib-server-parsers.lib")
#pragma comment(lib, "libcppnetlib-uri.lib")


int _tmain(int argc, _TCHAR* argv[])
{
 using namespace boost::network;
 /*
 if (argc != 2) {
  std::cout << "Usage: " << argv[0] << " [url]" << std::endl;
  return 1;
 }
 */

 char* uri = "http://127.0.0.1";

 http::client client;
// http::client::request request(argv[1]);
 http::client::request request(uri);
 request << header("Connection", "close");
 http::client::response response = client.get(request);
 std::cout << body(response) << std::endl;

 return 0;
}

 

 

결과>

b
Hello World
0


계속하려면 아무 키나 누르십시오 . . .

 

 

,
Technical Article 2012. 2. 27. 20:51

Boost::ASIO 사용을 위한 1.48.0 빌드 (VS2005)

다운 & 압축해제
http://boost.org

bjam, b2 빌드
 D:\Vendor 경로 기준

cd D:\Vendor\boost_1_48_0\tools\build\v2

bootstrap.bat

b2 install --prefix=D:\Vendor\boost_1_48_0

set path=%path%;D:\Vendor\boost_1_48_0\bin



 boost 빌드

cd D:\Vendor\boost_1_48_0

bjam --toolset=msvc --build-type=complete --with-system --with-thread --with-date_time --with-regex --with-serialization stage


D:\Vendor\boost_1_48_0\bin.v2\libs 
*.lib 파일 적당한(?)곳에 복사 후 사용



기타
vs2010, vs2005가 둘다 설치되어 있으면 vs2010으로만 빌드가 됨 ㅡㅡ;;
환경변수 때문인듯 한데... 아시는분은 답글 좀 달아주세요 ^^;





,
Technical Article 2009. 2. 13. 20:49

Boost 1.38.0 Test만 빌드하는 방법

UnitTest를 위한 프레임웍을 살펴보던중 UnitTest++과 Boost::Test가 가장 눈에 띄었다.

UnitTest++ 다운 후 간단히 빌드가 되지만 Boost::Test를 사용하기 위해서는 몇가지 빌드 과정이 필요하다.

<준비>
XP+sp3, VS2005, boost 1.38.0

1. http://www.boost.org/ 에서 download로 가서 boost_1_38_0 파일을 다운로드

2. 압축을 풀고 tools/jam/src에서 build.bat 실행
   혹시 에러가 발생한다면
   (1) Path가 너무 많을때
   (2) 시작-프로그램-Microsoft Visual Studio 2005-Visual Studio Tools-Visual Studio 2005 명령프롬프트를 실행해서 해당 경로로 이동해서 실행

3. 해당 경로 밑에 bin.ntx86/bjam.exe가 생성됨.

D:\boost_1_38_0\tools\jam\src\bin.ntx86>set path=%path%;D:\boost_1_38_0\tools\jam\src\bin.ntx86

4. bjam으로 test release/debug 모두 빌드
D:\boost_1_38_0\libs\test\build>bjam -sBUILD=boost_unit_test_framework --toolset=msvc --build-type=complete

  인자 : 빌드옵션(release +  debug = complete)


시간 무지하게 걸린다 ㅡㅡ;;
,
마이크로소프트웨어 2008. 9. 23. 09:06

Boost Spirit을 이용한 파서 구현(원문)

[마이크로소프트웨어]  2008년 1월 초고

Boost Spirit을 이용한 파서 구현

-------------------------------------

이근호 fiadot@gmail.com |

현재 인제대학교 컴퓨터 공학과 재학중이며, 온라인 게임 개발 업체인 NeonSoft R&D팀에서 서버 엔진을 개발 하고 있다. http://www.fiadot.com

--------------------------------

콤마(,)를 구분자로 사용한 문자열을 나눌 때, 간단한 메일주소나 URL이나 좀 더 복잡한 HTML이나 XML을 분석할 때 같이 형식을 다루고 싶을 때 우리는 구문분석기(Parser)를 떠올리게 된다. 간단하게 스트링 함수들을 이용해서 구현 할 수도 있고, Lex&Yacc(Flex&Bison), ANTLR 같은 도구를 사용해서 제작할 수도 있다. 단순 스트링 함수들을 조합해서 만들면 재사용성이 어렵게 되고, 나중에 다시 본다면 그냥 다시 만들고 말지 하는 생각이 들것이다. 툴을 이용하게 되면 툴 사용법에 대해 익히는데 시간을 소모하게 된다. 재사용성과 문제해결이라는 요소 집중했을 때 Boost의 Spirit 라이브러리가 그 답이 될 수 있다.

Boost::Spirit

Boost라이브러리중 하나인 Spirit은 템플릿 메타프로그래밍을 이용해서 제작된 파서 프레임워크이다.(Spirit은 템플릿 라이브러리이기 때문에 http://spirit.sourceforge.net에서 spirit-1.8.5-miniboost 다운받아 압축을 해제하고 경로만 지정해주면 환경 설정은 끝난다.) C++의 템플릿을 이용하여 컴파일 시간에 EBNF문법 파서를 생성 한다. 별도의 툴이 필요 없으며, 문법 부분을 독립시켜 재사용성을 높일 수 있고, C++코드와 자유롭게 섞어서 사용할 수 있는 특징을 지닌다. STL과 연동할 수 있는 부분도 제공되어 유용성을 더욱 높여준다.

Spirit의 전체적인 흐름을 살펴보면 Scanner를 통해서 문자열을 입력받아 Parser를 통해 구문분석을 하고 Semantic Action을 통해 구조적인 데이터를 뽑아내는 흐름을 가진다. 이런 큰 틀을 상기하면서 예제를 통해
Spirit에 대해 살펴보도록 하자.


프로토콜 파싱과 코드 생성

간단한 프로토콜을 파싱하여 STL vector와 map에 담고, 이를 이용하여 코드를 생성하는 예제을 만들어서 Spirit에 대해 알아보도록 하자.

<리스트1> 미리 정의된 프로토콜

PKT_REQ_LOGIN

/*

stringID;

stringPwd;

*/

PKT_RES_LOGIN

/*

intLoginCode;

*/

<리스트2> 생성된 코드

struct S_PKT_REQ_LOGIN

{

stringID;

stringPwd;

};

struct S_PKT_RES_LOGIN

{

intLoginCode;

};

프로토콜을 EBNF로 구문형식을 나타내면 <리스트3>과 같다.

<리스트3>

digit ::= '0'|'1'|'2'|..|'8'|'9'

alpha ::= 'a'|'b'|..|'y'|'z'|'A'|'B'|..|'Y'|'Z'

alnum ::= alpha {[ alpha | digit ]}

name ::= alpha {[ alnum | '_' ]}

var_type ::== "string" | "int"

var ::= var_type name ';'

protocol ::= name "/*" <var>* "*/"

조금 복잡해 보이는데 간략하게 정리하면, ::=의 왼쪽은 구분자(identifier)에 해당하고 오른쪽은 실제 정의내용이 위치한다. [,]는 0혹은 1을 의미하는 optional 심볼이다. {,}, * 은 반복되는 것을 표현한다. |는 or을 의미한다. 정리하자면 숫자와 문자를 정의하고 그것을 토대로 변수이름이나 프로토콜이름을 지정한 것을 볼 수 있다.

이것을 바로 Spirit구문으로 변형하면 <리스트4>의 모습이 된다.

<리스트4>

name = alpha_p >> *(alnum_p | '_');

var_type = str_p("string") | str_p("int");

var = (var_type >> name) >> ch_p(';');

protocol = name >> confix_p("/*", *var ,"*/");

변하는 부분은 ::=는 =, 순서대로 있는 공백에 해당하는 구분자는 >>, 반복의 의미는 * 스트링은 str_p를 붙이고, /* */의처럼 쌍을 이르는 부분은 confix_p로 바꿔주면 된다. 추가적으로 없거나 하나 존재하는 +도 있다.

여기서 주의해야 할 것은 *는 postfix가 아니라 prefix이고, 0이거나 반복을 의미임을 명심해야 한다.

Spirit에서 기본적으로 문자, 숫자, 혼합형태, pair, 문자열, 정수형, 실수형등 _p의 형태를 지닌 다양한 primitive 타입을 제공하고 있다. 그래서 실제 우리가 원하는 문법에 좀 더 집중할 수 있다. 그럼 Grammer와 Rule을 적용한 소스를 보자.

Grammer, Rule

<리스트5> 프로토콜을 파싱하는 Rule을 적용한 Grammer

template<class Action>

struct sp_grammer : boost::spirit::grammar<sp_grammer<Action>>

{

sp_grammer(Action& action_) : action(action_) {}

template<typename ScanT>

struct definition

{

rule<ScanT> r, protocol, name, var_type, var;

definition(sp_grammer const& self)

{

Action& action = self.action;

name = alpha_p >> *(alnum_p | '_'); // 이름

var_type = str_p("string") | str_p("int"); // 변수 타입

var = (var_type >> name)[action.var] >> ch_p(';'); // 변수 선언 protocol = name[action.ID]

>> confix_p("/*", *var ,"*/")[action.Protocol]; // 프로토콜 r = *protocol;

}

rule<ScanT> const& start() const

{

return r;

}

};

Action& action;

};

전체적인 형태를 보면 spirit의 grammar를 상속하여 구조체를 생성해서 내부적으로 문법을 정의함을 볼 수 있다. 진입점으로 protocol의 반복을 사용하여 여러 개의 프로토콜을 파싱할 수 있게 구성하였다. 여기까지가 파서에 해당하는 내용이다.

파싱된 자료를 토대로 실제 데이터를 집어넣어야 하는데, 그 부분이 바로 [ ]로 표현된 부분은 다음에 설명할 sementic action과 관련된 부분이다.

Semantic Actions

Semantic Action은 expression[action]의 형태로 사용되는데 매칭될 expression의 문자열이나 숫자형을 action에게 전달하는 기능을 한다. 이것은 구문분석과 자료저장을 분리시켜 코드의 재활용성을 높여주는 Spirit의 가장 중요한 기능이다.

<리스트5>에서 Action을 붙여서 사용된 Grammer는 <리스트6>을 통해 실제 저장이 된다.

<리스트6> 프로토콜을 vector와 map에 저장하는 Action

struct ProcotolAction

{

typedef vector<string> VarDef;

typedef map<string, VarDef> ProtocolDef;

ProtocolDef m_Protocol;

VarDef m_Var;

string m_ID;

ProcotolAction() : ID(m_ID), Protocol(m_Protocol, m_ID, m_Var), var(m_Var) {}

struct ID_a

{

ID_a(string& ID) : ID_(ID) {}

template<typename Iter>

void operator()(Iter first, Iter last) const

{

std::cout << "ID = " << string(first, last) << endl;

ID_ = string(first, last);

}

string& ID_;

} ID;

struct Protocol_a

{

Protocol_a(ProtocolDef& Protocol, string& ID, VarDef& Var)

: Protocol_(Protocol), ID_(ID), Var_(Var) {}

template<typename Iter>

void operator()(Iter first, Iter last) const

{

Protocol_.insert(make_pair(ID_, Var_));

Var_.clear();

}

ProtocolDef& Protocol_;

VarDef& Var_;

string& ID_;

} Protocol;

struct var_a

{

var_a(VarDef& Var) : Var_(Var) {}

template<typename Iter>

void operator()(Iter first, Iter last) const

{

std::cout << "var = " << string(first, last) << endl;

Var_.push_back(string(first, last));

}

VarDef& Var_;

} var;

};

ProcotolAction은 프로토콜의 이름과 변수(타입,이름) 벡터를 담은 맵을 통해서 자료를 저장한다. <리스트5>의 protocol = name[action.ID] 부분에서 매칭되는 구문이 나왔을 때

ID_a의 operator()를 호출하게 된다. 이때 인자로 Iterator는 const char*가 되어 시작과 끝을 표시해준다. 이를 통해 해당 문자열을 뽑아오게 된다. (참고 : int_p[action.ID]를 하게 되면 operator()(int n)의 형태를 구현해주어야 한다.)

parse

우리가 위에서 구현한 Grammer와 Action을 통해 다음과 같이 실행시킬수 있다.

<리스트6> 사용예

ProcotolAction s;

sp_grammer<ProcotolAction> g(s);

parse_info<const char* const> info = parse(buffer, g, space_p | ch_p('\t') | ch_p('\n'));

parse의 buffer는 스트링을 담고있는 버퍼에 해당하고, g는 Grammer에 Action을 템플릿인자로 적용한 파서이다. 3번째 인자는 buffer에서 skip할 구문을 집어넣게 되는데 여기서는 빈칸과 탭, 캐리지리턴을 삭제해서 사용했다. 이는 문법에 따라 어떤 것을 넘어가야 될지 정해주는 부분이다.

맺음말

간단한 예제를 통해 Spirit의 파싱과 결과 저장에 대해서 알아보았다.

프로젝트를 진행할 때 파싱을 해야 되는 경우가 많이 있는데, 적용해본다면 Spirit의 강력함을 체감 할 수 있을 것이다. 좀 더 효율성을 위한 파스트리와 STL바인더 부분은 Spirit User's Guide페이지를 참고해서 프로젝트에 적용해보길 바란다.

-------------------------------

참고 자료

http://spirit.sourceforge.net/

http://www.ddj.com/cpp/184401692

http://www.cl.cam.ac.uk/~mgk25/iso-14977.pdf

http://ideathinking.com/wiki/index.php/Article:RuleBasedSpirit

-------------------------------

,
TOTAL TODAY