# TCmalloc (Thread-Caching memory allocation)

https://code.google.com/p/gperftools/

- 구글이 만든 성능 도구에 포함되어 있는 힙 메모리 할당자로서 크롬 및 많은 프로젝트에 사용 

- 기존의 malloc 으로 대표되는 할당자의 경우 멀티쓰레드의 최적화가 고려되지 않은 상황의 구현체이기 때문에, Thread가 난무하는 현실 세계에서는 많은 성능 저하가 있다고 함 (메모리 할당, 관리도 동시성을 고려해야 하므로..)

- 이쪽 계열 라이브러리 중에서는 가장 많이 알려져 있고, 기본 할당기에 비해 비약적인 성능 향상이 있다고 함.

- 그리고 적용 방법도 드라마틱 하게, 인상적임. 



# 리눅스(Ubuntu, 14.10) 환경에서의 TCmalloc 

- 패키지로 설치 하던가, 소스를 받아서 설치 하면 됨  

sudo apt-get install libtcmalloc-minimal4


* 사용하는 방법 3가지 

1. tc_malloc 및 tc_free 등의 함수를 사용하여 malloc 이나 C++의 기본 할당자를 직접 대체하는 방법


2. 라이브러리를 링크하여 C 및 C++ 기본 할당자는 대체하는 방법

TCmalloc는 라이브러리를 링크하는 것 만으로, C 및 C++의 기본 할당자를 tmalloc의 할당자로 대체 해줌.(Patch)

g++ -o mybin mybin.cpp -ltcmalloc_minimal 


3. LD_PRELOAD를 이용하여 모듈을 먼저 로드(후킹)시킨 후, 기본 할당기를 대체하는 방식 

허나 구글에서는 이 방법에 대해서는 tricky 한 방법이므로, 2번 방법을 사용 하도록 권고함

LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so mybin

http://gperftools.googlecode.com/git/doc/tcmalloc.html

 

* 성능 

- 극단적인 할당과 해제를 반복하는 멀티쓰레드 환경에서, 기본 할당자 보다 3배이상 빠른 결과를 보임

- 물론 일반적인 로직의 경우 메모리 할당, 해제에 관련해서 비중이 얼마나 많이 차이나느냐에 따라 다르겠지만, 메모리 할당에서의 성능 향상 뿐만 아니라, 지속적이 서비스로 인한 메모리 단편화를 감소시켜 바꾸는 것만으로 20% 정도의 성능 향상을 보인 다고 함.

  


# 윈도우 환경에서의 TCmalloc 

- 소스 받아서 MSVC로 설치 하면 됨. 친절하게 MSVC 프로젝트 파일로 제공 됨  

- 솔루션에 많은 프로젝트들이 보이는데, libtcmalloc_minimal 라고 되어 있는 프로젝트만 Release 로 빌드하면, 동적링크 모듈(DLL)로 빌드되고 정적으로 바꾸고 빌드해서 사용해도 무방한 것으로..


* 사용하는 방법 2가지 

1. 위의 리눅스의 예와 같음. TCmalloc의 커스텀 할당자로 구현 하면 됨


2. 위도우 환경에서는 Patch 방식이 되지 않으므로, 라이브러리만 링크하는 것으로 끝나지는 않고 강제로 링크 심볼을 정의 함으로서 기본 할당자가 교체 되도록 설계 함 (이것도 멋짐!!)

// 소스에 아래와 같이 추가하여 라이브러리 참조 및 링크 심볼을 주입 함 

#pragma comment (lib, "libtcmalloc_minimal")

#pragma comment (linker, "/include:__tcmalloc") 


// 프로젝트 속성 환경에서 추가 할때는,  

// 구성속성-링커-입력-추가종속성 에 명시하여 링크를 추가하고, 

// 밑에 "강제 기호 참조"에 __tcmalloc 를 넣어주면 됨


* 성능 

- 극단적인 환경에서는 30% 이상 효과가 있고, 일반적인 업무 로직에서는 그보다는 작겠지만 어느정도 성능 향상 효과가 있을 것으로 판단.

- 기본적으로 MSVC 환경에서의 메모리 할당자가 리눅스쪽의 것보다는 좋아 보임.


--


# JEMalloc 

- Jason Evans가 만들었고, 페이스북이나 파이어폭스에서 사용 한다고 함

- 성능은 TCmalloc 보다 약간 좋다고는 (주장)하나, 개인적으로 테스트 할때는 TCmalloc 보다 약간 부족 했음.

- 구글링의 결과로는 보다 다이나믹한 멀티쓰레드 환경에서 최적화 되었다는데 반복적인 할당과 해제를 반복하는 예제에서는 그다지 많은 차이를 보이지 않음.


# 리눅스 환경에서의 JEMalloc

http://www.canonware.com/jemalloc/

- TCmalloc 과 같이 소스 및 패키지 설치 지원 

sudo apt-get install libjemalloc-dev


* 사용하는 방법 

- 위의 TCmalloc과 같이 JEMalloc의 커스컴 할당기(je_malloc, je_free) 를 사용 하던가 LD_PRELOAD를 이용하여 사용하는 방법이 있음 

- JEMalloc도 링크 만으로 기본 할당자를 교체 해주나, C언어의 기본 할당자 malloc 계열만 교체 해주고 C++의 것은 교체 해주지 않음. 그래서 C++에서 사용하려면(STL 등에서) 사용자 정의 할당자를 만들고 그 곳에 JEMalloc으로 할당 하는 방식으로 처리해야 함

- 리눅스의 경우 C, C++ 할당자를 모두 교체 지원 함


- 윈도우의 경우도 링크 참조만으로 기본 할당기를 교체해주지는 않고, header 파일을 이용해서 매크로로 C언어 기본 할당자를 교체 해주는 방식으로 처리 (#include <jemalloc/jemalloc.h>)

- Mingw (gcc 4.9.2)에서는 컴파일이 잘되나, MSVC(2013) 에서는 컴파일이 몇가지 문제를 일으킴 

Github에 Win32용 포팅 버전이 있으므로 그것을 받아서 빌드 하면 됨  


# 기타

- nedmalloc : 윈도우즈 환경에 더 최적화 되었다는 nedmalloc 이런것도 있음. nedmalloc의 경우 자체 C언어 계열 커스텀 할당 함수와 C++의 allocator 를 대체할 클래스도 제공.


- tbbmalloc (Threading Building Blocks) : 인텔에서 만든 쓰레딩관련 라이브러리에 포함 되어 있는 힙 메모리 할당기 

- 사이트에서 다운 받으면 OS별 바이너리가 들어 있음.

// linux 

sudo apt-get install libtbb-dev

g++ -o mybin mybin.cpp -ltbbmalloc_proxy


// MSVC, tcmalloc 과 같은 방식

#pragma comment (lib, "tbbmalloc_proxy")

#pragma comment (linker, "/include:___TBB_malloc_proxy") 



Detours Express 3.0Detours is a library for intercepting arbitrary Win32 binary functions on x86 machines.

// 설치 후, 설치 디렉토리에서 nmake 로 빌드 후 사용 

// dll 프리로드 후킹 (Windows)

withdll.exe /d:libtcmalloc_minimal.dll mybin




# 추가, 윈도우 테스트 결과 (참고용) 

소스 : https://gist.github.com/cdecl/e7b414e8eff4a67c9396


* vc++ 기본 (msvc 2013)

[std::string alloc]

1585, 1656, 1600, 1707, 1628,

[malloc()]

1451, 1411, 1381, 1489, 1399,


* tcmalloc 

[std::string alloc]

1156, 1150, 1195, 1045, 1184,

[malloc()]

560, 586, 564, 571, 564,


* tbbmalloc (Threading Building Blocks)

[std::string alloc]

1003, 973, 963, 998, 1000,

[malloc()]

811, 782, 780, 813, 807,



# 추가, 리눅스 테스트 결과 (참고용) 

- 소스 : malloc 반복횟수 및 옵티마이저 안되게 끔 위의 소스 수정 


* 기본 (g++ 4.9.1)

[std::string alloc]

3931, 3904, 3945, 3902, 4044,

[malloc()]

1434, 1422, 1447, 1457, 1411,


* tcmalloc

[std::string alloc]

1112, 1125, 1161, 1099, 1091,

[malloc()]

355, 333, 328, 351, 334,


* jemalloc

[std::string alloc]

1451, 1442, 1396, 1427, 1411,

[malloc()]

438, 483, 432, 462, 457,


* tbbmalloc

[std::string alloc]

1856, 1843, 1820, 1868, 1842,

[malloc()]

750, 701, 765, 764, 752,



참고 : 

one malloc to rule them all

http://blog.reverberate.org/2009/02/one-malloc-to-rule-them-all.html


Scalable memory allocation using jemalloc

https://www.facebook.com/notes/facebook-engineering/scalable-memory-allocation-using-jemalloc/480222803919


Benchmarks of the Lockless Memory Allocator

http://locklessinc.com/benchmarks_allocator.shtml


C++ memory allocation mechanism performance comparison (tcmalloc vs. jemalloc)

http://stackoverflow.com/questions/7852731/c-memory-allocation-mechanism-performance-comparison-tcmalloc-vs-jemalloc

cdecl/asb 개발 중..


1. wg/wrk (Modern HTTP benchmarking tool)

- wrk는 커맨드 라인의 옵션으로, 간단한게 Http 서비스의 성능 평가를 할 수 있는 툴.

- 윈도우 환경에서도 쓸 수 있지 않을까 했지만, Linux의 aio(Asynchronous I/O)으로 구현 되어 있어 포팅 불가.

- 비슷한 툴로 Apache ab, JoeDog/siege 등이 있으며, github에 "benchmark" 등의 단어로 검색하면 더 많은 언어로 작성되어 있는 오픈소스를 찾아 볼 수 있음.


2. Boost Asio

- 윈도우 환경이라면 IOCP로 작성 가능 하겠지만, 기본적으로 작성해야 할 내용이 많고 크로스 플랫폼을 지원하고 성능적인 부분에서 검증이 되어 있는 Asio로 작성 

- boost 라이브러리는 소스 및 필요한 바이너리만 컴파일 하여 사용. (system, regex, date-time, thread) 

- regex나 thread의 경우 이미 C++11에 포함 되어 있지만 Asio 구현체가 Boost 것을 사용 함. 


3. Visual C++ 2013 

- 가장 C++11이 적합한 VC++ 컴파일러.  

- boost 및 openssl 의 경우 NuGet 으로 편하게 라이브러리를 추가해서 사용 할 수 있음. 

- boost는 NuGet의 버전이 낮고, 위에 언급한 이유로 별도로 빌드 하여 사용 함. 그리고 x64 staitc 빌드에서 crt 관련 링크 에러가 발생? 


4. g++ 4.9.1 

- ubuntu 환경에서 g++로 컴파일. 

- hyper-v 환경에서 ubuntu 14.04로 개발 테스트를 하다, 이후 14.10으로 변경. 

- g++가 문법적으로는 C++11을 VC++에 비해 더 잘 지원하는것 같으나, 기본 라이브러리가 아직 C++11에 미흡한 것들이 있음.

- std::regex 는 아직 지원을 하지 않아 boost::regex를 사용. 찾아보니 버전 5. 이상에서 지원할 것이라 추측.

- std::stringstream 의 swap 및 move ctor를 지원하지 않음.  

- OpenSSL의 경우 apt-get 패키지로 설치. 


5. Git

- 윈도우 버전의 경우 Git과 같이 배포되는 *nix 의 커맨드라인 툴이 유용함.

- tortoies-git 을 사용하는데, 몇가지 명령어는 svn 식으로 표현 된것 같음.


6. SSL (OpenSSL)

- asio에서 지원하는 ssl 코드를 사용해서 ssl 내부적인 내용까지는 구현이 필요 없었음. (다행히도..)


7. 성능 

- 환경 Laptop Intel i5(4세대), 4 Core, 8G RAM, Windows 8.1 64bit (Ubuntu 14.04 on hyper-v , 4 core, 1G RAM)  


- 윈도우 환경에서는, 최적의 옵션의 경우, IIS(local, static html) 초당 40,000 이상 호출 결과.

- 윈도우 환경 최대 연결 개수는 약 26,000 클라이언트 개수까지 테스트 

  

- Ubuntu (on hyper-v) 환경에서는, Nginx(local, static html) 호출, 초당 35,000 이상 호출 결과.

- Ubuntu 환경 최대 연결 개수를 약 30,000 클라이언트 개수까지 테스트 

- wrk 에 비해 성능이 10~20% 정도 떨어지는 것 같음. (상황에 따라 좀 다른 결과)


8. 전략 

- 기본적인 Thread 생성 개수는, 메인 + io_service 개수 + 사용자 Thread 개수가 생성이 됨

- io_service를 Thread 별로 생성을 한다면, -t 4 옵션의 경우 9개가 생성됨

- io_service는 한개만 생성하고 io_service::run() 를 사용자 Thread 에서 실행한다면, -t 4 옵션의 경우 5개 생성

- 테스트 결과 io_service per thread VS io_service::run() per thread 성능상 별 차이 없어 보여서 적게 생성되는 방향 정리.



* 기타 

- 개발 중, Http Client 모듈 수정하여 http_client 라이브러리 만듬 



cdecl/asbHttp benchmarking and load test tool for windows, posix

- wg/wrk (Modern HTTP benchmarking tool)과 기능이 비슷한, Windows 버전으로 만들게 된 커맨드 라인 툴.

- boost::asio 와 asio 에서 지원하는 ssl(openssl)을 이용하여 구현.

- VC++ 2013 환경에서 개발하고, 라이브러리 패키지 NuGet으로 관리.

- Posix 환경은 g++ (4.8 이상, -std=c++11), boost 라이브러리 및 libssl-dev (openssl) 패키지 설치  


# 테스트 결과 

- 테스트 환경 ; Laptop Intel i5(4세대), 4 Core, 8G RAM, Windows 8.1 64bit  

- 성능 좋은 결과가 나오기 위해서는 대체적으로 Core 1/2 개수의 Thread에, Core 10배수 정도의 Connection이 무난해 보임 (로컬 환경에서 테스트 할때)

성능 좋은 결과가 나오기 위해서는 대체적으로 Core 개수의 Thread에, Core 20배수 정도의 Connection이 무난해 보임

asb -d 10 -t 2 -c 40 http://localhost/index.html

> Start and Running 10s (2015-03-18.17:36:10)

  http://localhost/index.html

    40 connections and 2 Threads

> Duration         : 10000ms

    Latency        : 0.02ms

    Requests       : 426149

    Response       : 426109

    Transfer       : 147.11MB

> Per seconds

    Requests/sec   : 42610.90

    Transfer/sec   : 14.71MB

> Response Status

    HTTP/1.1 200   : 426109


# Windows 에서 최대 Connection 만들기 

- OS의 소켓 최대 포트 번호를 늘림 (초기값 : 1500, 변경: 50000)

   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters 의 MaxUserPort 값 변경  

https://support.microsoft.com/ko-kr/kb/196271?wa=wsignin1.0

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

편집 메뉴에서 새로 만들기를 클릭하고 다음 레지스트리 항목을 추가합니다.

값 이름: MaxUserPort

값 형식: DWORD

값 데이터: 65534

유효 범위: 5000-65534(십진수)

기본값: 0x1388(십진수 5000)

설명: 이 매개 변수는 프로그램이 시스템에서 사용 가능한 사용자 포트를 요청할 때 사용되는 최대 포트 번호를 제어합니다. 일반적으로 수명이 짧은 임시(ephemeral) 포트에는 1024에서 5000 사이의 값이 할당됩니다. 보안 공지 MS08-037 릴리스 후 Windows Server 2003의 동작이 Windows Server 2008 및 Windows Vista의 동작과 보다 근접하게 일치하도록 변경되었습니다. Microsoft 보안 공지 MS08-037에 대한 자세한 내용은 다음 문서 번호를 클릭하여 Microsoft 기술 자료 문서를 참조하십시오.

- IIS의 응용프로그램의 큐 길이를 늘림 (초기값 : 1000, 변경: 3000), Worker Thread 개수 늘림 (초기값: 1, 변경: 2)

- IIS의 경우, 경로를 http://localhost/ 이렇게 줘서 Default 파일을 찾는 과정이 생각보다 느림 (20% 성능)

- 현재 조건(랩탑)에서는 최대 26,000 연결 정도 까지 가능하고 27,000 연결 이상 테스트 하면 문제가 발생함 (리소스가 부족한 것으로 추측)

- http://sockettools.com/kb/maximum-socket-connections/

asb -d 20 -t 3 -c 26000 http://localhost/index.html
> Start and Running 20s (2015-03-18.18:14:41)
  http://localhost/index.html
    26000 connections and 3 Threads
> Duration         : 20038ms
    Latency        : 0.09ms
    Requests       : 239424
    Response       : 213426
    Transfer       : 76.26MB
> Per seconds
    Requests/sec   : 10671.30
    Transfer/sec   : 3.81MB
> Response Status
    HTTP/1.1 200   : 213426




# Ubuntu 에서 최대 Connection 만들기 
- 테스트 환경 : Ubuntu 14.04 on hyper-v , (4 core, 1G RAM)
- 현재 상태 확인 : ulimit -a       
- OS의 소켓(파일) 개수를 늘려 줌 (/etc/security/limits.conf 파일 수정)
# 추가 
*               soft    nofile            65535
*               hard    nofile            65535
*               soft    nproc            65535
*               hard    nproc            65535
 
- nginx 설정 수정 
# nginx.conf 
worker_processes auto;
worker_rlimit_nofile 100000;
 
events {
    # worker_connections 1024;
    # 1024 x 16 
    worker_connections 16384;
    use epoll;
    multi_accept on;
}

# sites-available/default
# 모니터링용 페이지 노출 
location /nginx_status {
# Turn on stats
stub_status on;
access_log   off;
# only allow access from 192.168.1.5 #
# all
allow all;
}

- 클라이언트의 운영방식 인지, 서버의 운영방식 때문인지는 모르겠지만 4000 이상은 안올라 가는 것 같음 ( wrk 도 비슷한 결과 )
- 가상머신 임에도 불구하고, 30,000 연결 까지는 가능한 듯 (nginx 작업 프로세스 수 변경). 물론 처리량은 형편없이 떨어지지만.. 
- 이론상 서버 연결 가능한 수 :  worker_connections x worker_processes = 16384 x 4 = 65536
asb$ asb -d 20 -t 3 -c 30000 http://localhost/index.html
> Start and Running 20s (2015-03-18.14:50:05)
  http://localhost/index.html
    30000 connections and 3 Threads
> Duration         : 68805ms
    Latency        : 2.49ms
    Requests       : 56867
    Response       : 27585
    Transfer       : 28.10MB
> Per seconds
    Requests/sec   : 1379.25
    Transfer/sec   : 1.40MB
> Response Status
    HTTP/1.1 200   : 27585



# http://localhost/nginx_status 
Active connections: 30002 
server accepts handled requests
 30010 30010 36553 
Reading: 0 Writing: 1 Waiting: 30001 


Github : https://github.com/philsquared/Catch

Tutorial : https://github.com/philsquared/Catch/blob/master/docs/tutorial.md


# 특징

- CppUnit, Google Test, Boost.Test 등등 다른 프레임웍크에 비해 의존성이 없는 헤더파일(catch.hpp) 하나면 사용 할 수 있음 

  * C++ Test Framework 비교 

- 별도 빌드 모듈로 운영 할 수도 있음

- 크로스 플랫폼 지원


# 사용 

- TEST_CASE 라는 기본 단위 테스트에 SECTION이라는 작은 부분으로 나누어서 테스트 할 수 있음

- 기본적으로 REQUIRE 와 CHECK 의 평가식을 이용하여 로직 검증. 

- REQUIRE 와 CHECK 차이점은, REQUIRE는 평가 실패 시 진행을 중지하고 다음 SECTION 이나 TEST_CASE 로 이동하는 반면, CHECK는 평가 결과와 관계없이 바로 다음 평가를 실행 

- REQUIRE_FALSE, CHECK_FALSE - 실패 평가 (NOT 조건)  

- REQUIRE_THROWS, CHECK_THROWS - 예외가 발생하면 성공 

- REQUIRE_NOTHROW, CHECK_NOTHROW - 예외가 발생하지 않으면 성공 

- INFO, WARN, FAILD - 각 실패 단계에 따른 메세지 출력

- CAPTURE - 주어진 식과 값 출력 (테스트 실패시 노출)

#define CATCH_CONFIG_MAIN - 메인함수 자동으로 생성 및 실행 


# 결론

- 진입장벽 낮으며 사용하기 편리하고 다른 테스트 프레임워크 만큼 많은 기능 제공하는듯

- 살짝 아쉬운점은 출력이 좀더 반듯? 하게 나왔으면 하는 생각. 


# 예제

 
#include <iostream>
#include <string>
#include <memory>
using namespace std;
 
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
 
TEST_CASE("std::string", "test")
{
string s = "abcedf";
 
REQUIRE(s.capacity() > 0);
 
SECTION("TEST 1") {
REQUIRE(s.length() > 0);
REQUIRE(s[0] == 'a');
string ss(move(s));
CAPTURE(ss);
 
CAPTURE(s.capacity());
REQUIRE(s.capacity() == 0); // FAILED
REQUIRE(ss.length() > 0);
}
 
s = "ab";
 
SECTION("TEST 2") {
REQUIRE_THROWS([]{ throw "error"; }());
REQUIRE_THROWS(s.at(5) = 'e');
REQUIRE_NOTHROW(s.at(0) = 's');
 
}
}
 
 
TEST_CASE("std::shared_ptr", "test")
{
auto sp = std::make_shared<string>("init");
CHECK(sp);
 
auto sp2 = sp;
CHECK(sp.use_count() == 2);
 
weak_ptr<string> wp = sp;
CHECK(sp.use_count() == 2);
 
SECTION("WeakPtr 1") {
auto spp = wp.lock();
CAPTURE(sp.use_count());
CAPTURE(spp.use_count());
CHECK(spp.use_count() == 3);
}
 
sp.reset();
sp2.reset();
 
SECTION("WeakPtr 2") {
auto spp = wp.lock();
CAPTURE(sp.use_count());
CAPTURE(spp.use_count());
CHECK(spp); // FAILED
}



# 결과




'Dev > C++' 카테고리의 다른 글

cdecl/asb 개발 중..  (0) 2015.04.01
cdecl/asb - Http benchmarking and load test tool for windows, posix  (0) 2015.03.18
C++ REST SDK (casablanca) 간단 샘플  (0) 2015.02.17
[C++11] Variadic template  (0) 2014.11.02
boost 설치  (0) 2013.11.20

2021년 신규 작성 

C++ REST SDK(cpprestsdk) Sample

 

C++ REST SDK(cpprestsdk) Sample

Introduction https://github.com/Microsoft/cpprestsdk Microsoft에서 만든 클라이언트, 서버용 C++ HTTP 통신 모듈이며, JSON URI, 비동기, 웹소켓, oAuth 등을 지원 C++11의 비동기, 병렬 프로그램 모델 지원 크로스 플랫

cdecl.github.io

--

 

https://casablanca.codeplex.com/

 

The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.

 

What's in the SDK:

  • Features - HTTP client/server, JSON, URI, asynchronous streams, WebSockets client, oAuth
  • PPL Tasks - A powerful model for composing asynchronous operations based on C++ 11 features
  • Platforms - Windows desktop, Windows Store, Windows Phone, Ubuntu, OS X, iOS, and Android
  • Support for Visual Studio 2012, 2013, and 2015 with debugger visualizers
  • NuGet package with binaries for Windows and Android platforms

 

- Microsoft에서 만든 클라이언트, 서버용 C++ HTTP 통신 모듈이며, JSON URI, 비동기, 웹소켓, oAuth 등을 지원 

- C++11의 비동기, 병렬 프로그램 모델 지원

- 크로스 플랫폼 지원 등..

- XML 파서도 지원 해줬으면 하는 아쉬움이...

 

 

# 설치방법

https://casablanca.codeplex.com/documentation

- openssl 및 boost 라이브러리 필요 

- 리눅스(g++)는 소스를 다운 받아 CMake를 이용하여 make 파일 생성, 빌드 및 설치 

  ** 설치시 Release/include/cpprest/details/http_constants.dat 파일이 누락이 되어 수동으로 복사 해줌 (Ubuntu 14.04)

- 윈도우(VC++)는 프로젝트 파일 포함, VS로 열어서 컴파일 하면 됨. 

  그러나 그냥 Nuget 패키지로 설치하면 바이너리와 include 파일을 쉽게 받음.

- 기본적으로 동적 링크(dll, so) 파일로 생성 

 

 

# 간단 예제 소스 

- U("") 는 _T("") 와 비슷한, UNICODE 및 MBCS 환경의 문자열 타입을 스위칭 해주는 매크로. 

  허나 U는 _T와는 다르게 _WIN32 환경이면 기본으로 _UTF16_STRINGS으로 정의되어 있어 프로젝트의 문자집합의 세팅과 관계 없이 UNICODE와 같은 환경으로 동작 

  리눅스 환경에서는 다른 설정을 해주지 않는 이상 char, std::string으로 정의 

utility::string_t은 std::string과 std::wstring을 스위칭 해주는 타입 

- 대체적인 패턴은, 동기는 .get(), 비동기는 then().wait() 조합으로 사용

 

 

#include <iostream>
using namespace std;
 
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
#pragma comment(lib, "cpprest120_2_4") // windows only
using namespace utility; // Common utilities like string conversions
using namespace web; // Common features like URIs.
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
using namespace concurrency::streams; // Asynchronous streams
 
 
void GetHttp()
{
http_client client(U("http://en.cppreference.com/w/"));
auto resp = client.request(U("GET")).get();
 
wcout << U("STATUS : ") << resp.status_code() << endl;
wcout << "content-type : " << resp.headers().content_type() << endl;
wcout << resp.extract_string(true).get() << endl;
}
 
void GetHttpAsync()
{
http_client client(U("http://en.cppreference.com/w/"));
 
client.request(U("GET")).then([](http_response resp){
wcout << U("STATUS : ") << resp.status_code() << endl;
wcout << "content-type : " << resp.headers().content_type() << endl;
 
resp.extract_string(true).then([](string_t sBoby){
wcout << sBoby << endl;
}).wait();
 
}).wait();
 
}
 
 
void GetJson()
{
http_client client(U("http://date.jsontest.com/"));
 
http_request req(methods::GET);
 
client.request(req).then([=](http_response r){
wcout << U("STATUS : ") << r.status_code() << endl;
wcout << "content-type : " << r.headers().content_type() << endl;
 
//{
// "time": "11:25:23 AM",
// "milliseconds_since_epoch" : 1423999523092,
// "date" : "02-15-2015"
//}
 
r.extract_json(true).then([](json::value v) {
wcout << v.at(U("date")).as_string() << endl;
wcout << v.at(U("time")).as_string() << endl;
}).wait();
 
}).wait();
 
}
 
int main(int argc, char* argv[])
{
wcout.imbue(locale("kor")); // windows only
 
GetHttp();
GetHttpAsync();
GetJson();
 
return 0

}

 

 

# Variadic template
  - template 에서 타입의 인자를 가변으로 처리 할 수 있는, 새로운 ... 표현식이이 생겼다 

  - http://en.wikipedia.org/wiki/Variadic_template 


  - 그리고 또 다른 설명인 MSDN의 링크 
     
http://msdn.microsoft.com/ko-kr/library/dn439779.aspx

variadic 템플릿 함수를 통합하는 대부분의 구현은 일부 양식의 재귀를 사용하지만 전통적인 재귀와는 약간 다릅니다. 전통적인 재귀는 같은 서명을 사용하여 자신을 호출하는 함수를 포함합니다. (오버로드하거나 템플릿화할 수 있지만 매번 동일한 시그너처가 선택됩니다.) Variadic 재귀에는 다른 수의 인수(거의 항상 줄어듦)를 사용하여 variadic 함수 템플릿을 호출하는 작업이 포함되므로 매번 다른 서명을 사용하지 않게 됩니다. "기본 사례"는 여전히 필요하지만 재귀적 특성은 다릅니다.

그렇다 대부분 재귀로 구현을 하게끔 되어 있고, 메타 프로그램의 기법과 같다.


  - template <typename...Ty> 라는 형식으로 사용 되며 이렇게 사용된 형식은 가변적으로(0~N개) 파라미터를 받아 드릴수 있다

  - 이렇게 받은 파라미터는 재귀함수 형식으로 다시 자기 함수를 호출 (Ty...var) 하게 되며, 파라미터가 앞에서 부터 하나씩 제거 되는 형식으로 다음 함수에 전달 되게 된다

  - 그리고 마지막 end 조건되 되는 별도의 비가변 template 함수를 호출함으로서 종료 되게 끔 동작 함 

 

# 예제 
  - 첫번째로 만들어 본 예제는 vector에 모들 가변 파라미터를 넣어 보는것
  - 재귀 개념으로 실행 되며 마지막에 실행 되는 end 역활로 비가변 템플릿 함수가 실행 되고 끝냄
  - vector의 성능 향상을 위해 C++11 에 포함된 rvalue 레퍼런스를 이용한 move semantics 를 사용하고 마지막 조건 부터 역으로 push 되는 방식을 사용하여 데이터가 template 전달 역순으로 배열 됨.

  - 정상적인 순으로 받아드리게 할려면 별도의 파라미터 vector<T> 로 받아서 넣게 하면 될듯.

  - vector를 사용하여 구조상 한개의 타입으로 한정 지을 수 밖에(다른 타입을 대입하면 vector에서 에러 분출..) 없지만 variant 타입을 사용 한다면 문제가 없고, C++11의 구현으로 실제 std::tuple의 경우 Variadic template으로 구현 되어 있음 


#include <iostream> #include <vector> #include <string> using namespace std; template <typename Ty> vector<Ty> MakeVector(const Ty& p) { vector<Ty> v; v.push_back(p); return std::move(v); } template <typename Ty, typename...VARS> vector<Ty> MakeVector(const Ty& p, VARS...vs) { vector<Ty> v = MakeVector(vs...); v.push_back(p); return std::move(v); } int main() { auto v = MakeVector(1, 3, 5, 7, 9, 11, 13); for (int &n : v) { cout << n << endl; } }


# 결과 (재귀의 역순으로 push 를 해서 역으로 결과가 나옴)

13
11
9
7
5
3
1





# 응용
  - C++에서 COM 을 사용하기 위한 방법 중, 디스패치 인터페이스를 사용하기 위해서는 약간의 수고가 필요한데 그것을 좀 더 편하게 사용하게 사용하기 위한 클래스를 만든 적이 있다. 그 클래스는 동적인 파라미터를 처리하기 위해 40개의 오버로딩으로 처리한 이력이 있음. ( 이것 때문이었을까?, VB 6 의 경우 파라미터 개수가 30개가 MAX 인듯)
  - 물론 printf 류 함수에서 사용하는 것을 사용 할 수 있지만, 이것은 타입을 정확히 알아야 하고 안정성 측면에 보장 살 수가 없음.
  - 기존 구현은 ATL의 _variant_t 를 사용하여 40개의 오버로딩 까지 구현 했으나, C++11 을 새로운 기능인 Variadic template을 이용하여 2개 오버로딩으로 끝냄.

  - _variant_t 특성상 여러 타입을 대입 할 수 있어 vector<_variant_t> 가 템플릿 가변 인수를 처리 할 수 있음


# COMDispatchV.h


// COMDispatch.h: interface for the IDispatch class.
//////////////////////////////////////////////////////////////////////
 
#ifndef _DISPATCH_H_20011012_BY_CDECL_
#define _DISPATCH_H_20011012_BY_CDECL_
 
#include <comdef.h>
#include <vector>
 
 
#define BYREF(x) GLASS::COMDispatch::ToRefParam((x))
 
namespace GLASS {
 
 
class COMDispatch
{
public:
typedef std::vector<_variant_t> vec_param;
typedef _variant_t PT;
 
// Proxy Class
class Proxy
{
public:
void SetParent(COMDispatch *p) { pDisp_ = p; }
void SetPropName(const _bstr_t &bstrName) { bstrName_ = bstrName; }
 
_variant_t operator=(const _variant_t &var) const
{
pDisp_->PutProperty(bstrName_, var);
return var;
}
 
operator _variant_t() const {
return pDisp_->GetProperty(bstrName_);
}
 
_variant_t operator() ()
{
vec_param vecParams;
return pDisp_->Call(bstrName_, vecParams);
}
 
template <typename...VARS>
_variant_t operator() (VARS...param)
{
vec_param vecParams = Param(param...);
return pDisp_->Call(bstrName_, vecParams);
}
private:
 
template <typename Vartype>
vec_param Param(Vartype p)
{
vec_param v;
v.push_back(p);
 
return std::move(v);
}
 
template <typename Vartype, typename...VARS>
vec_param Param(Vartype p, VARS...vs)
{
vec_param v = Param(vs...);
v.push_back(p);
 
return std::move(v);
}
 
private:
COMDispatch *pDisp_;
_bstr_t bstrName_;
};
 
public:
COMDispatch() : spDispatch_(NULL) { proxy_.SetParent(this); }
COMDispatch(const COMDispatch &disp) : spDispatch_(disp.spDispatch_) { proxy_.SetParent(this); }
explicit COMDispatch(const _variant_t &var) : spDispatch_(var) { proxy_.SetParent(this); }
COMDispatch(const char *) = delete;
COMDispatch(const wchar_t *) = delete;
virtual ~COMDispatch() { Release(); }
 
COMDispatch& operator=(const COMDispatch &disp);
COMDispatch& operator=(const _variant_t &var);
 
public:
_variant_t Call(const _bstr_t &bstrMethodName, vec_param &vecParams);
 
void PutProperty(const _bstr_t &strPropName, const _variant_t &var, bool bRef = false);
_variant_t GetProperty(const _bstr_t &strPropName);
 
virtual Proxy& operator[](const _bstr_t &bstrPropName);
 
virtual void CreateObject(const _bstr_t &bstrProgID);
virtual void Release();
 
public:
virtual void GetIDsOfNames(const _bstr_t &bstrMethodName, DISPID &lDispID);
 
protected:
virtual void Invoke(const DISPID lDispID, vec_param &vecParams, _variant_t &varRetVal, 
const WORD wFlags = DISPATCH_METHOD);
 
public:
static _variant_t ToRefParam(_variant_t &var);
 
protected:
Proxy proxy_;
IDispatchPtr spDispatch_;
};
 
 
 
 
 
//////////////////////////////////////////////////////////////////////
// Dispatch implementation
 
COMDispatch& COMDispatch::operator=(const COMDispatch &disp)
{
if (this != &disp) {
spDispatch_ = disp.spDispatch_;
proxy_.SetParent(this);
}
 
return *this;
}
 
 
COMDispatch& COMDispatch::operator=(const _variant_t &var)
{
spDispatch_ = var;
proxy_.SetParent(this);
 
return *this;
}
 
void COMDispatch::Release()
{
if (spDispatch_ != NULL) {
spDispatch_.Release();
}
}
 
void COMDispatch::CreateObject(const _bstr_t &bstrProgID)
{
HRESULT hr = spDispatch_.CreateInstance((LPCSTR)bstrProgID);
 
if (FAILED(hr)) {
_com_raise_error(hr);
}
}
 
_variant_t COMDispatch::Call(const _bstr_t &bstrMethodName, vec_param &vecParams)
{
DISPID lDispID;
GetIDsOfNames(bstrMethodName, lDispID);
 
_variant_t varRetVal;
Invoke(lDispID, vecParams, varRetVal);
 
return varRetVal;
}
 
 
COMDispatch::Proxy& COMDispatch::operator[](const _bstr_t &bstrPropName)
{
proxy_.SetPropName(bstrPropName);
return proxy_;
}
 
 
void COMDispatch::PutProperty(const _bstr_t &strPropName, const _variant_t &var, bool bRef)
{
DISPID lDispID;
GetIDsOfNames(strPropName, lDispID);
 
vec_param vecParams;
vecParams.push_back(var);
 
_variant_t varRetVal;
Invoke(lDispID, vecParams, varRetVal, bRef ? DISPATCH_PROPERTYPUTREF : DISPATCH_PROPERTYPUT);
}
 
_variant_t COMDispatch::GetProperty(const _bstr_t &strPropName)
{
DISPID lDispID;
GetIDsOfNames(strPropName, lDispID);
 
vec_param vecParams;
 
_variant_t varRetVal;
Invoke(lDispID, vecParams, varRetVal, DISPATCH_PROPERTYGET);
 
return varRetVal;
}
 
 
void COMDispatch::GetIDsOfNames(const _bstr_t &bstrMethodName, DISPID &lDispID)
{
BSTR bstrMN = static_cast<BSTR>(bstrMethodName);
 
HRESULT hr = spDispatch_->GetIDsOfNames(IID_NULL, &bstrMN, 1, LOCALE_SYSTEM_DEFAULT, &lDispID);
 
if (FAILED(hr)) {
_com_raise_error(hr);
}
}
 
 
void COMDispatch::Invoke(const DISPID lDispID, vec_param &vecParams, _variant_t &varRetVal, const WORD wFlags)
{
DISPPARAMS dispparams = { 0 };
DISPID dsipid_put = DISPID_PROPERTYPUT;
 
if (DISPATCH_PROPERTYGET != wFlags) {
dispparams.cArgs = vecParams.size();
dispparams.rgvarg = (vecParams.size() == 0) ? NULL : &vecParams.front();
 
if ((DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF) & wFlags) {
dispparams.rgdispidNamedArgs = &dsipid_put;
dispparams.cNamedArgs = 1;
}
}
 
HRESULT hr = spDispatch_->Invoke(
lDispID,
IID_NULL,
LOCALE_USER_DEFAULT,
wFlags,
&dispparams,
DISPATCH_PROPERTYPUT == wFlags ? NULL : &varRetVal,
NULL,
NULL
);
 
if (FAILED(hr)) {
_com_raise_error(hr);
}
}
 
 
_variant_t COMDispatch::ToRefParam(_variant_t &var)
{
_variant_t varRet;
varRet.vt = VT_BYREF | VT_VARIANT;
varRet.pvarVal = &var;
 
return varRet;
}
 
 
} // end namespace
 
  

#endif // _DISPATCH_H_20011012_BY_CDECL_



<예제, boost::asio 필요 라이브러리 >

# msvc-14.0 : vc++ 2015

# msvc-12.0 : vc++ 2013

# 64bit : address-model=64

bjam.exe toolset=msvc-11.0 link=static runtime-link=static --with-system --with-date_time --with-regex --with-thread -j 4 stage






출처 : http://www.viper.pe.kr/cgi-bin/moin.cgi/Boost


3.1. bjam 사용법 [Bottom] [Top]

Boost 라이브러리는 대부분 Template 으로 구성되어 있다. 하지만 regex, thread 와 같이 빌드가 필요한 라이브러리를 포함하고 있다. bjam 은 이런 라이브러리들을 빌드와 설치를 자동화 해주기 위한 프로그램으로 직접 빌드해서 사용해도 되고 아래의 링크에서 다운받아서 사용해도 된다.

  • 다운로드 - http://sourceforge.net/project/showfiles.php?group_id=7586&package_id=72941&release_id=643622

  • 사용법
    bjam [options] [properties] [install|stage]
    
  • Targets 과 관련 옵션 ([install|stage], [options])
    install
    헤더 파일과 빌드된 라이브러리 파일을 설치한다.
    --prefix=<PREFIX>

    플랫폼에 종속적이지 않은 파일(헤더 파일)을 설치할 경로를 지정한다. (기본값: [Win32] C:\Boost, [Unix계열] /usr/local)

    --exec-prefix=<EPREFIX>

    플랫폼에 종속적인 파일(바이너리 파일)을 설치할 경로를 지정한다. (기본값: <PREFIX>)

    --libdir=<DIR>

    라이브러리 파일을 설치할 경로를 지정한다. (기본값: <EPREFIX>/lib)

    --includedir=<HDRDIR>

    헤더 파일을 설치할 경로를 지정한다. (기본값: <PREFIX>/include)

    stage
    빌드된 라이브러리 파일만 설치한다.
    --stagedir=<STAGEDIR>

    라이브러리 파일을 설치할 경로를 지정한다. (기본값: ./stage)

  • 기타 옵션 ([options])
    --build-type=<type>
    미리 정의된 빌드 타입 중에서 빌드될 타입을 지정한다. 단, 각 라이브러리에서 지원하는 빌드 타입에 한해서 빌드 가능하다.
    minimal (기본값)

    - 릴리즈 모드(빌드 속성: "release <threading>multi <link>shared <link>static <runtime-link>shared")만 빌드한다.

    complete
    - 가능한 모든 타입(릴리즈/디버그, 정적/동적, 싱글/멀티 쓰레드 등)의 라이브러리를 빌드한다.
    --build-dir=DIR
    빌드 시 사용될 임시 디렉토리를 지정한다.
    --show-libraries
    빌드가 필요한 라이브러리를 보여준다.
    --layout=<layout>
    Boost 의 다양한 버전에 대한 라이브러리 파일 이름과 헤더 파일의 위치를 결정하거나 동일 시스템에서 여러 컴파일러를 사용할 경우 사용한다.
    versioned (기본값)

    - 라이브러리(바이너리) 파일의 이름에 버전, 라이브러리 이름, 컴파일러 버전을 포함한다. Boost 헤더 파일은 Boost 버전이 포함된 이름으로 생성된 <HDRDIR> 의 하위 디렉토리에 설치된다.

    system

    - 라이브러리(바이너리) 파일의 이름에 버전, 라이브러리 이름, 컴파일러 버전을 포함하지 않는다. Boost 헤더 파일은 <HDRDIR> 디렉토리에 설치된다. 이 옵션은 배포 패키지를 빌드하기 위하여 준비된 옵션이다.

    --buildid=ID
    빌드된 라이브러리 파일 이름에 지정된 ID 를 추가한다. 기본적으로는 어떤 것도 추가되지 않는다.
    --help
    도움말을 보여준다.
    --with-<library>
    지정된 라이브러리만 빌드 후 설치한다.
    --without-<library>
    지정된 라이브러리를 빌드하지 않는다. (기본값: 모든 라이브러리를 빌드한다.)
  • 빌드 속성 ([properties])
    toolset=toolset
    컴파일러를 지정한다. (VC++일 경우: msvc 사용)
    variant=debug|release
    릴리즈 또는 디버그 모드로 빌드할지 선택한다.
    link=static|shared
    정적 또는 동적(공유) 라이브러리로 빌드할지 선택한다.
    threading=single|multi
    멀티 쓰레드 지원 여부를 선택한다.
    runtime-link=static|shared
    C/C++ Runtime 라이브러리를 정적 또는 동적(공유) 라이브러리로 링크할지 선택한다.
  • 중요 옵션 ([options])
    --clean
    Targets 을 정리(제거)한다.
    -a
    라이브러리를 재빌드(Rebuild)한다.
    -n
    빌드 명령을 실행하지 않고, 출력만 한다.
    -d+2
    실행되는 빌드 명령을 출력한다.
    -d0
    빌드 메시지를 출력하지 않는다.
    -q
    에러 발생 시 작업 과정을 중지한다.
    --debug-generator
    빌드 과정과 명령을 상세히 출력한다.
    --debug-configuration
    환경 설정 사항(요구사항 검사)을 포함하여 빌드 과정과 명령을 상세히 출력한다.
    --debug-building
    Targets 의 빌드 속성을 포함하여 빌드 과정과 명령을 상세히 출력한다.
  • 빌드가 필요한 라이브러리 (--show-libraries 옵션으로 확인 가능)

    • date_time (./)

    • filesystem (./)

    • graph
    • graph_parallel
    • iostreams (./)

    • math
    • mpi
    • program_options (./)

    • python
    • random
    • regex
    • serialization
    • signals (./)

    • system (./)

    • test
    • thread (./)

    • wave

3.2. 라이브러리 네이밍(Library Naming) [Bottom] [Top]

For example, libboost_regex-vc71-mt-d-1_34.lib can be broken down into the following elements:

lib

Prefix: except on Microsoft Windows, every Boost library name begins with this string. On Windows, only ordinary static libraries use the lib prefix; import libraries and DLLs do not.

boost_regex

Library name: all boost library filenames begin with boost_.

-vc71

Toolset tag: identifies the toolset and version used to build the binary.

-mt

Threading tag: indicates that the library was built with multithreading support enabled. Libraries built without multithreading support can be identified by the absence of -mt.

-d

ABI tag: encodes details that affect the library's interoperability with other compiled code. For each such feature, a single letter is added to the tag:

  • Key

    Use this library when:

    s

    linking statically to the C++ standard library and compiler runtime support libraries.

    g

    using debug versions of the standard and runtime support libraries.

    y

    using a special debug build of Python.

    d

    building a debug version of your code.

    p

    using the STLPort standard library rather than the default one supplied with your compiler.

    n

    using STLPort's deprecated “native iostreams” feature.

    For example, if you build a debug version of your code for use with debug versions of the static runtime library and the STLPort standard library in “native iostreams” mode, the tag would be: -sgdpn. If none of the above apply, the ABI tag is ommitted.
-1_34

Version tag: the full Boost release number, with periods replaced by underscores. For example, version 1.31.1 would be tagged as "-1_31_1".

.lib

Extension: determined according to the operating system's usual convention. On most unix-style platforms the extensions are .a and .so for static libraries (archives) and shared libraries, respectively. On Windows, .dll indicates a shared library and .lib indicates a static or import library. Where supported by toolsets on unix variants, a full version extension is added (e.g. ".so.1.34") and a symbolic link to the library file, named without the trailing version number, will also be created.




'Dev > C++' 카테고리의 다른 글

C++ REST SDK (casablanca) 간단 샘플  (0) 2015.02.17
[C++11] Variadic template  (0) 2014.11.02
boost::asio 클라이언트 소켓 (timeout 기능)  (0) 2010.10.14
이미지 변환 모듈 (모바일용, GDI+)  (0) 2010.06.22
C++0x, RValue Reference  (0) 2009.05.27

- 메세지를 한번 주고 받고 세션을 종료하는 클라이언트 소켓
- boost::asio 라이브러리 사용 (boost 의 date_time, thread, system 컴파일 필요)
- boost::asio::deadline_timer 를 이용하여 timeout 기능 구현 
- 비동시 소켓으로 구현한 동기 소켓(?)



#pragma once

#include <algorithm>
using namespace std;

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;


struct IsEOF_Basic
{
bool operator()(const std::string &)
{
return true;
}
};



template <class Ty = IsEOF_Basic>
class ClientSocket 
{
public:
ClientSocket() : socket_(io_service_), timeout_(io_service_), nResponse_(0) {}

~ClientSocket() 
{
Close();
}

bool Connect(const string &sIP, const string &sPort) 
{
bool bResult = false;

tcp::resolver resolver(io_service_);
tcp::resolver::query query(tcp::v4(), sIP, sPort);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;

boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket_.close();
socket_.connect(*endpoint_iterator++, error);
}

if (!error) {
bResult = true;
}
return bResult;
}

void Send(const string &s, const int nTimeout = 5)
{
copy(s.begin(), s.end(), szBuff);

socket_.async_write_some(boost::asio::buffer(szBuff, s.length()),
boost::bind(&ClientSocket::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

timeout_.expires_from_now(boost::posix_time::seconds(nTimeout));
timeout_.async_wait(boost::bind(&ClientSocket::Timeout, this));

handle_read_wait();
}

int WaitForResponse()
{
socket_.io_service().reset();

while (socket_.io_service().run_one()) 
{
if (nResponse_) break;
}

return nResponse_;
}

void Close()
{
socket_.close();
}

std::string GetReadBuffer()
{
return sReadBuff_;
}

enum { TIMEOUT = -1, READY = 0, SUCCESS = 1 };

private:
void Timeout()
{
nResponse_ = TIMEOUT;
}

void handle_read_wait() 
{
socket_.async_read_some(boost::asio::buffer(szBuff, BUFF_SIZE),
boost::bind(&ClientSocket::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

nResponse_ = READY;
}

void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
if (error) {
Close();
return;
}

sReadBuff_.append(szBuff, szBuff + bytes_transferred);

if (IsEOF(sReadBuff_)) {
nResponse_ = SUCCESS;
}
else {
handle_read_wait();
}
}

void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
if (error) {
Close();
return;
}
}

private:
boost::asio::io_service io_service_;

boost::asio::deadline_timer timeout_;
tcp::socket socket_;
std::string sReadBuff_;
volatile int nResponse_;

Ty IsEOF;
enum { BUFF_SIZE = 8192};
char szBuff[BUFF_SIZE];
};

int SendPacket (
LPCSTR strIP, LPCSTR strPort, int nTimeoutSecond, LPCSTR szMessage, LPSTR szRetMessage)
{
int nResult = -2;

try {
typedef ClientSocket<> ClientSocketType;
ClientSocketType socket;

if (!socket.Connect(strIP, strPort)) {
throw -1;
}

if (nTimeoutSecond == 0) nTimeoutSecond = 5;

socket.Send(szMessage, nTimeoutSecond);
int nResponse = socket.WaitForResponse();

if (nResponse == ClientSocketType::TIMEOUT) {
throw 0;
}

if (nResponse == ClientSocketType::SUCCESS) {
std::string s = socket.GetReadBuffer();
std::copy(s.begin(), s.end(), szRetMessage);

nResult = s.size();
}
}
catch (int nErr) {
nResult = nErr;
}
catch (...) {}

return nResult;
}



'Dev > C++' 카테고리의 다른 글

[C++11] Variadic template  (0) 2014.11.02
boost 설치  (0) 2013.11.20
이미지 변환 모듈 (모바일용, GDI+)  (0) 2010.06.22
C++0x, RValue Reference  (0) 2009.05.27
C++0x Lambda  (0) 2009.05.20
- 이미지의 포맷 변환 및 퀄러티, 크기조정(비율) 모듈 
- Windows 환경, C++, GDI+, Component


STDMETHODIMP CMobileImage::Convert(BSTR Src, BSTR Output, BSTR ImgFormat, long Quality, long Width, long Height, VARIANT_BOOL* pSuccess)
{
*pSuccess = VARIANT_FALSE;

_bstr_t bstrSrc(Src);
_bstr_t bstrOutput(Output);
_bstr_t bstrImgFormat(ImgFormat);

ULONG_PTR gdiToken;
Gdiplus::GdiplusStartupInput gdiInput;
Gdiplus::GdiplusStartup(&gdiToken, &gdiInput, NULL);

try {
std::auto_ptr<Gdiplus::Image> pImage(Gdiplus::Image::FromFile((LPCWSTR)bstrSrc));
if (!pImage.get()) {
throw -1;
}

CLSID m_pngClsid;
if (GetEncoderClsid((LPCWSTR)ImgFormat, &m_pngClsid) == -1) {
throw -1;
}
else {
Gdiplus::EncoderParameters params;
params.Count = 1;
params.Parameter[0].Guid = Gdiplus::EncoderQuality;
params.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
params.Parameter[0].NumberOfValues = 1;

long Value = Quality;
params.Parameter[0].Value = &Value;

if (Width > 0 && Height > 0) {
std::auto_ptr<Gdiplus::Bitmap> pResize(new Gdiplus::Bitmap(Width, Height, PixelFormat24bppRGB));
std::auto_ptr<Gdiplus::Graphics> pGrap(Gdiplus::Graphics::FromImage(pResize.get()));
pGrap->DrawImage(pImage.get(), 0, 0, Width, Height);

pResize->Save((LPCWSTR)bstrOutput, &m_pngClsid, &params);
}
else {
pImage->Save((LPCWSTR)bstrOutput, &m_pngClsid, &params);
}
}

*pSuccess = VARIANT_TRUE;
}
catch (...) { }

Gdiplus::GdiplusShutdown(gdiToken);

if (m_spObjectContext) { m_spObjectContext->SetComplete(); }

return S_OK;
}


int CMobileImage::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
using namespace Gdiplus;

UINT  num = 0;          // number of image encoders
UINT  size = 0;         // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1;  // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1;  // Failure

GetImageEncoders(num, size, pImageCodecInfo);

for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;  // Success
}    
}

free(pImageCodecInfo);
return -1;  // Failure
}

'Dev > C++' 카테고리의 다른 글

boost 설치  (0) 2013.11.20
boost::asio 클라이언트 소켓 (timeout 기능)  (0) 2010.10.14
C++0x, RValue Reference  (0) 2009.05.27
C++0x Lambda  (0) 2009.05.20
C++0x 지원 컴파일러 목록  (0) 2009.05.20
C++0x RValue Reference 라는것이 추가 되었다.


RValue Reference는  Move semantics와 Perfect forwarding 이라는 두가지 기능을 가진다.


1. Move semantics

기존 부터 있던 Reference는 LValue Reference 라고 불린다.

int n = 10;
int &r = n;  // LValue Reference
int *p = &n;  // 포인터 참조 방식
cout << r << " " << *p << endl;

C++의 참조는 내부적으로 포인터를 사용하여 참조를 하게 되지만 사용함에 있어 보다 우아하게(?) 사용을 할 수 있다는 장점이 있다.


반면 RValue Reference는 아래와 같이 사용한다.

int n = 10;
int &&r =n; // 그런데 기존 참조랑 머가 틀리냐??

int, long 등의 기본 타입과 기존 클래스의 복사생성자, 대입연산자에 대해서는 RValue Reference 참조는 기존 Value Reference와 똑같이 동작을 한다.

하지만 RValue Reference는 객체(변수)의 주소를 참조하는 기존의 LValue Reference와 틀리게,
RValue Reference 로 겹지정한 복사생성자 및 대입연산자를 따로 구현, 그리고 그것을 의도적으로 호출하게 할 수 있다.

그리고 그 RValue Reference 로 겹지정한 복사생성자 및 대입연산자에는,
임시객체애 대해서 복사가 아닌  메모리를 이동 (Move) 하는 방법으로 임시 객체의 생성및 소멸에 대한 비용을 줄이는 구현이가능해 진것이다.

소유권 이전 기법을 사용하는 auto_ptr 처럼..



class Item
{
  public:
    Item() : p(new char[100]) {}
    Item(const Item &t) : p(new char[100]) {  memcpy(p, t.p);  } // 복사생성자
    Item(Item &&t) : p(t.p) { t.p = NULL;  } // Move 생성자

    // Item& operator=(const Item &t) { return *this; } // 대입연산자
    // Item& operator=(Item &&t) { return *this; } // Move 대입 연산자
    // ...
   ~Item() { if (p) delete p; }
  
  private:
    char *p;
};

Item&& foo()
{
  Item item;
  // ...
  return item;
}

int main()
{
  Item item;
  Item t = item; // 복사생성자 호출
  Item &r = item; // 참조

  Item &&rr = Item; // 참조
  Item &&mv = std::move(item);  // Move 생성자
  Item &&mvt = foo(); // // Move 생성자
}

위의 코드와 같이 foo() 함수에서 RValue Reference로 리턴을 하게 되면,
Item 객체의 RValue Reference 버전의 Move 생성자가 호출되고
Move 생성자에서 내부 멤버인 포인터의 소유권을 이전하여 임시객체에 대해서 필요 없는 생성-소멸의 과정을 거치지 않게끔 할 수 있는것이다.

그리고 강제로 Move 생성자, Move 대입 연산자를 호출 하기 위해서 std::move() 함수를  이용 할 수도 있다.


C++0x 의 STL에는 RValue Reference 의 코드가 적용 되어 있어 사용하는 것 만으로도 성능 효과를 볼 수가 있다고 한다.
대략 다음과 같은 코드..

std::string s = "s";
std::string str;
str = s + "t" + "r" + "i" + "g";  // 임시객체 (RValue Reference) 사용



2. Perfect forwarding

template 의 내부 함수가 참조 및 상수의 값을 파라미터로 받을 경우 관련되서 여러 개의 버전 구현을 해야하는 문제를,
RValue Reference의 문법으로 하나로 처리 하는 내용.
(자세한 내용은 아래링크 -_-; )



참고 : http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx


'Dev > C++' 카테고리의 다른 글

boost::asio 클라이언트 소켓 (timeout 기능)  (0) 2010.10.14
이미지 변환 모듈 (모바일용, GDI+)  (0) 2010.06.22
C++0x Lambda  (0) 2009.05.20
C++0x 지원 컴파일러 목록  (0) 2009.05.20
C++ Refactoring  (0) 2009.04.14
아래 링크의 글 중 Herb Sutter 의 Lambda 예제 및 설명에 관한 리플..
http://herbsutter.wordpress.com/2008/03/29/trip-report-februarymarch-2008-iso-c-standards-meeting/

[]와 []안에 들어가는 내용에 대해서 명쾌하게 설명을..




Herb Sutter

Re binders: Okay, I give! I’ll use a better example next time.

(no name) asked: "How are local variables captured?" You have to specify whether it’s by copy or by reference. So this example is illegal because it tries to use a local variable:

    int numWidgets = 0;
    for_each( v.begin(), v.end(), []( Widget& w )
    {
        ++numWidgets;  // error, numWidgets is not in scope
    } );

If you want to update numWidgets directly, capture it by reference:

    for_each( v.begin(), v.end(), [&numWidgets]( Widget& w )
    {
        ++numWidgets;  // increments original numWidgets
    } );
    // numWidgets == v.size() here

Or use the shorthand [&] to take all captured variables implicitly by reference:

    for_each( v.begin(), v.end(), [&]( Widget& w )
    {
        ++numWidgets;  // increments original numWidgets
    } );
    // numWidgets == v.size() here

What if you want a local copy? You say to pass it by value, but for safety reasons the current proposal says you get a read-only copy that you can’t modify:

    for_each( v.begin(), v.end(), [numWidgets]( Widget& w )
    {
        int i = numWidgets; // ok
        ++i;
        // "++numWidgets;" would be an error
    } );
    // numWidgets == 0 here

Or use the shorthand [=] to take all captured variables implicitly by copy:

    for_each( v.begin(), v.end(), [=]( Widget& w )
    {
        int i = numWidgets; // ok
        ++i;
        // "++numWidgets;" would be an error
    } );
    // numWidgets == 0 here

Similarly, for the question: "What will happen in the following case:"

    int flag = 0;
    mypool.run( [] { flag = 1; } );
    cout << flag << endl;

The answer is that the code is illegal, you have to say whether you capture flag by value or by reference, which can be as simple as replacing [] with [=] or [&]. And if you capture by value, you get a read-only copy so you couldn’t assign to it.


'Dev > C++' 카테고리의 다른 글

이미지 변환 모듈 (모바일용, GDI+)  (0) 2010.06.22
C++0x, RValue Reference  (0) 2009.05.27
C++0x 지원 컴파일러 목록  (0) 2009.05.20
C++ Refactoring  (0) 2009.04.14
An Overview of the Coming C++ (C++0x) Standard  (0) 2008.12.29

'Dev > C++' 카테고리의 다른 글

C++0x, RValue Reference  (0) 2009.05.27
C++0x Lambda  (0) 2009.05.20
C++ Refactoring  (0) 2009.04.14
An Overview of the Coming C++ (C++0x) Standard  (0) 2008.12.29
asio C++ library  (0) 2008.08.22

+ Recent posts