boost에서 OpenSSL 사용하기 (2)

빌드된 OpenSSL을 프로젝트 설정에 넣고 다시 빌드해본다.

include를 해야한다.

#include <boost/asio/ssl.hpp>

를 하면 ssl 코드들을 가져온다.

라이브러리 설정에는 빌드된 OpenSSL 폴더의 lib 폴더 경로를 포함시켜줘야한다.

 

이렇게하고 빌드를 해보니…

빌드에 오류가 생겼다.

에러 메시지를 구글에 다시 검색해보니,

https://stackoverflow.com/questions/37522654/linking-with-openssl-lib-statically

링크에서 답을 찾을 수 있었다. http://wiki.openssl.org/index.php/Compilation_and_Installation 에 가서 enable-capieng 이라는 옵션에 대해 찾아보라는 얘기였다.

해당 문서에서 enable-capieng 으로 검색해보니

Enables the Microsoft CAPI engine on Windows platforms. Used to access the Windows Certificate Store. Also see Using Windows certificate store through OpenSSL on the OpenSSL developer list.

라는 내용이 있었다.

빌드 옵션에 추가한다.

perl Configure VC-WIN64A –D:\ –openssldir=D:\Library\OpenSSL enable-capieng no-shared no-asm threads

이렇게 하고 다시 openssl을 빌드해본다.

 

이 옵션으로 해결되지 않아서 -d 옵션 추가. -d 옵션을 추가했더니 nmake 과정에서 알 수 없는 옵션이라는 에러메시지가 나오는 것을 확인했다.

 

빌드옵션을 변경했다.

perl Configure VC-WIN64A –prefix=D:\Library\OpenSSL –openssldir=D:\Library\OpenSSL –debug no-shared no-idea no-mdc2 no-rc5 no-asm no-capieng threads enable-ssl-trace enable-static-engine

 

이렇게 빌드했더니 오류가 절반 정도 사라졌다. 나머지 링킹 오류는 라이브러리 파일을 인식하는 위치에서 추가적인 라이브러리 파일을 불러들여야 했다.

.lib 파일을 불러들이는 곳에서 다음을 추가한다. (혹은 프로젝트 설정에서 해도 된다.)

#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")

이렇게하고 빌드하니 오류 없이 빌드가 되었다.

 

참고했던 자료들

  • https://github.com/openssl/openssl/blob/OpenSSL_1_1_0-stable/INSTALL
  • https://www.lesstif.com/pages/viewpage.action?pageId=6291508
  • http://www.programmersought.com/article/8711142745/
  • https://github.com/libevent/libevent/issues/59

boost에서 OpenSSL 사용하기 (1) : 윈도우에서 OpenSSL 빌드

boost에서 OpenSSL을 사용하기 위해서는 먼저 OpenSSL 설치가 필요하다. boost의 ssl 관련 파일들에서 openssl 관련 파일들을 인클루드해오기 때문이다.

검색엔진을 찾아보다가, https://jethro.tistory.com/entry/CC-Windows에서-OpenSSL-써먹기 를 참고했다.

 

Step 1. ActivePerl 설치

https://www.activestate.com/products/activeperl/ 로 이동해서 ActivePerl 을 설치한다.

 

Step 2. OpenSSL 소스 다운로드

https://www.openssl.org/source/ 에서 소스코드를 다운로드한다. 난 1.1.1j 버전을 다운로드했다.

 

Step 3. Configure 설정

perl Configure VC-WIN32 –openssldir=C:\OpenSSL-x86-debug no-shared no-asm threads

를 입력하라고 하는데 64비트 윈도우이니 VC-WIN64A 로 입력. (VC-WIN64I 도 있긴한데 아마 Itanium 아키텍쳐일 때 쓰라는 것일 것 같다.)

다음과 같은 오류가 발생.

dmake나 nmake가 필요한 것 같다.

안내 받은대로 ppm install dmake 를 입력하면, 이런저런 패키지들을 설치한다.

 

다시 configure 명령어 입력.

perl Configure VC-WIN64A –openssldir=D:\Library\OpenSSL no-shared no-asm threads

별 문제 없이 끝났다.

 

Step 4. make

그런데 참고하고 있는 블로그 글에는 ms\do_ms.bat 파일이 있다고 했는데 그 위치에 해당 파일이 없다.

구글에 검색해보니…

https://stackoverflow.com/questions/39076244/why-there-is-no-ms-do-ms-bat-after-perl-configure-vc-win64a

1.1.0 버전부터는 그 명령어가 없어졌다고 한다. 그냥 nmake 를 입력하라고 되어있다.

nmake를 해보니 그런 명령어가 없다고 한다. 일반 cmd가 아니라 VS2015 x64 네이티브 도구 명령 프롬프트를 다시 실행해야한다.

 

다시 nmake 를 입력하면 빌드가 시작된다.

다 완료된 후 nmake test 를 입력하여 테스트. 테스트도 잘 완료되었다.

nmake install 을 입력했더니…

*** Installing runtime librariesCannot create directory C:/Program Files/OpenSSL: No such file or directoryNMAKE : fatal error U1077: 'C:\Perl64\bin\perl.exe' : '0x2' 반환 코드입니다.Stop.

에러로 중지된다. 으어…

구글에 검색해보니 나만 겪는 문제는 아닌듯하다. github에 이슈로 올라와있다.

https://github.com/openssl/openssl/issues/2034

댓글을 보고 configure 명령어에 prefix를 추가한다.

perl Configure VC-WIN64A –prefix=D:\Library\OpenSSL –openssldir=D:\Library\OpenSSL no-shared no-asm threads

다시 nmake clean, nmake, nmake test 실행.

다시 make install 을 실행하니 제대로 진행되었다.

 

빌드가 성공되면 prefix로 지정된 위치에 파일들이 생성된다.

OpenSSL 빌드는 끝.

boost 1.70.0 버전 업그레이드시 참고사항

boost를 1.60.0 버전을 계속 사용하다가 1.70.0으로 업그레이드하니 변경된 점이 많았다.

https://zepeh.tistory.com/498 를 참고한다.

ASIO에서 io_service가 io_context 로 변경되었다. 하지만 1.70.0 버전을 적용하면 io_service도 그대로 사용할 수 있긴 하다. cpp 파일과 h 파일도 그대로 들어있다. 비주얼스튜디오 인텔리센스에서도 io_context 가 바로 인식되지는 않는데, 이런 경우 전처리기 설정에서 BOOST_ASIO_NO_DEPRECATED 를 추가해주면 io_service 가 비활성화되고 io_context만 사용할 수 있게 된다.

io_context 로 코드를 바꾸고 나면 충돌사항들이 나오게 된다.

 

from_string 변경

from_string() 함수가 삭제되었다.

아래 코드를

boost::asio::ip::address_v4 address = boost::asio::ip::address_v4::from_string(server_ip, error_code);

아래처럼 변경한다.

boost::asio::ip::address_v4 address = boost::asio::ip::make_address_v4(server_ip, error_code);

이 문제도 해결.

 

strand.wrap() 변경

strand의 wrap() 함수도 변경되었다.

다음의 코드를

boost::asio::async_write(socket_,
            boost::asio::buffer(send_queue_.front().first, send_queue_.front().second),
            strand_.wrap(
                boost::bind(
                    &BasicSocket::OnSendHandler,
                    shared_from_this(),
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred
                )
            )
        );

아래처럼 변경한다.

boost::asio::async_write(socket_,
            boost::asio::buffer(send_queue_.front().first, send_queue_.front().second),
            boost::asio::bind_executor(strand_, boost::bind(
                &BasicSocket::OnSendHandler,
                shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
            )
        );

 

이 문제도 해결.

boost::property_tree의 위험성

.ini 파일을 파싱하기 위해 boost::property_tree 클래스를 사용했었다.

서버의 성능을 테스트하던 도중 어디사 CPU를 많이 잡아먹나 계속 테스트했는데 네트워크 전송 부분이 계속 문제였다. 아무리 수정을 해도 고쳐지지 않는 상황. 비주얼스튜디오의 성능프로파일러를 돌려보니 boost::property_tree 가 문제의 원인이었다. 환경설정에서 특정한 값을 가져오기 위해 쓰느 코드가 네트워크 속도를 느리게 만드는데 기여하고 있었다.

이 부분을 수정하고나니 CPU 점유율이 아주 낮아졌다.

boost를 마구 쓰면 안된다는걸 깨닫게되었네.

boost에서 메모리풀 사용

프로그램 구현 중 메모리풀이 필요한 경우가 있어 어떻게 할까 하다가 boost의 메모리풀을 찾아보게 되었다.

boost의 메모리풀은 4가지.

  1. pool
  2. singleton_pool
  3. pool_alloc
  4. object_pool

네가지 메모리풀 중에 어떤 것이 어떤 상황에 가장 적합한지는 많이 써봐야 알 수 있을듯하다. 찾아보니 내가 가지고 있던 몇몇 게임서버 소스는 singleton_pool을 사용하고 있는 케이스가 있었다. 이것부터 먼저 찾아보는 것으로.

singleton_pool은 다른 메모리풀 클래스들과는 다르게 스레드-세이프 특성을 지니고 있어서 가장 유용하게 쓰일 것 같다.

singleton_pool을 아래와 같은 코드로 좀더 편하게 사용 가능. 출처는 ‘아지크의 좌충우돌 IT 이야기’

#include <stdio.h>
#include <iostream>
#include <vector>
#include <boost/pool/singleton_pool.hpp>
#include <boost/pool/pool_alloc.hpp>


template<typename T,  unsigned int NEXT_SIZE = 32U, unsigned int  MAX_POOL_SIZE = 0U>
class CMemoryPoolT
{
public:
     static void* operator new(size_t size)
     {
          return boost::singleton_pool<T,
               sizeof(T),
               boost::default_user_allocator_new_delete,
               boost::details::pool::default_mutex,
               NEXT_SIZE,
               MAX_POOL_SIZE>::malloc();
     }

     static void operator delete(void* p)
     {
          boost::singleton_pool<T,
               sizeof(T),
               boost::default_user_allocator_new_delete,
               boost::details::pool::default_mutex,
               NEXT_SIZE,
               MAX_POOL_SIZE>::free(p);
     }
};


class CMemoryPoolTest  :public CMemoryPoolT<CMemoryPoolTest>
{
public:
     char Dumy[124] ;
};


int _tmain(int argc, _TCHAR* argv[])
{
     using std::vector ;

     CMemoryPoolTest *p = new CMemoryPoolTest() ;

     delete p ;

     printf("Using MemoryPool... \n") ;


     return 0;
}

프로그램 종료시에는 purge_memory()를 꼭 호출해주어야 한다고 한다.

혹은 다음과 같은 방법으로도 사용 가능하다.

struct SEND_BUFFER_TAG {};
typedef boost::singleton_pool<SEND_BUFFER_TAG, SEND_BUFFER_SIZE> SendBufferPool;

사용할 클래스의 헤더파일에서 위와 같이 선언. TAG를 여러개 사용하고 메모리풀마다 다르게 적용하면 서로 다른 메모리풀이 된다.

메모리를 할당 받고 싶다면,

char* send_data = static_cast<char*>(SendBufferPool::malloc()); // 메모리를 할당 받는다.

SendBufferPool::free(send_data); // 다 사용한 메모리를 해제한다.

종료시에는 당연히,

SendBufferPool::purge_memory();

를 호출해야한다.

출처와 참고사이트

 

윈도우에서 C++ Boost 사용하기

윈도우에서 C++ 작업시 유용한 Boost 라이브러리를 사용하기 위해서는 빌드를 해야한다. 파일시스템 등을 다루는 등의 운영체제에 의존하는 기능들을 사용하기 위해 빌드해야한다고 한다.

  1. http://www.boost.org 에 들어가서 Boost를 다운 받는다.
  2. 압축을 풀고 디렉토리에 들어가 bootstrap.bat 를 실행한다.

    2019. 05. 08.  추가
    boost 1.70 이 되면서 bootstrap.bat msvc 등처럼 컴파일러를 명시해서 입력해야 한다.
    지원되는 컴파일 옵션은 다음과 같다.

    Toolsets supported by this script are: borland, como, gcc, gcc-nocygwin, intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10, vc11, vc12, vc14, vc141

  3. b2 –help 를 실행해서 한번 도움말을 쭉 읽어본다.
  4. 윈도우 커맨드창을 열고 해당 다음의 명령을 입력하여 빌드를 시작한다. 64비트, 디버그/릴리즈 모두, 멀티쓰레드, MPI 사용 안함으로 빌드한다.
  5. b2 variant=debug,release link=static,shared threading=multi address-model=64 –without-mpi -j8 stage
  6. 빌드 옵션은 여러가지가 더 있다. 찾아봐서 자기가 필요한대로 설정한다.
  7. -j8은 몇개의 작업을 동시에 하는지를 결정한다. 4코어인 경우에는 -j4를 해주면 모든 코어를 다 사용하게 된다. 적당하게 설정하는 것이 좋다.

빌드에는 시간이 꽤 걸린다.

다음의 링크를 참조했다.

리눅스에서 boost 라이브러리 빌드하기

부스트 라이브러리를 리눅스에서 사용하기 위한 절차를 기록해본다.

내 서버의 경우는 CentOS 6.4 버전이며 yum을 이용해 최신의 업데이트가 모두 다 되어있는 상태다.

일단 boost.org에서 최신 소스를 받는다. 이 글을 쓰고 있는 2013년 10월 14일 기준으로 1.54 버전이 가장 최신이다. unix용으로는  tar.gz과 tar.bz2 형식으로 제공되고 있는데 아무래도 압축효율이 높은 bz2 파일을 다운 받았다.

적당한 디렉토리에 받은 파일을 놓고 bunzip2 명령을 이용해 압축을 해제하면 tar 파일이 나온다. tar xvf boost_1_54_0.tar 명령을 이용해서 압축을 해제한다.

압축을 해제한 디렉토리로 들어가서 ./bootstrap.sh 파일을 실행한다.

[root@83rpm boost_1_54_0]# ./bootstrap.sh
Building Boost.Build engine with toolset gcc... tools/build/v2/engine/bin.linuxx86_64/b2
Detecting Python version... 2.6
Detecting Python root... /usr
Unicode/ICU support for Boost.Regex?... not found.
Backing up existing Boost.Build configuration in project-config.jam.1
Generating Boost.Build configuration in project-config.jam...
Bootstrapping is done. To build, run:
./b2
To adjust configuration, edit 'project-config.jam'.
Further information:
- Command line help:
./b2 --help
- Getting started guide:
http://www.boost.org/more/getting_started/unix-variants.html
- Boost.Build documentation:
http://www.boost.org/boost-build2/doc/html/index.html
[root@83rpm boost_1_54_0]#

위와 같은 메시지가 나타난다.

메시지에 나타난대로 ./b2 명령어를 입력하면 빌드가 시작된다. 내 서버의 CPU는 Xeon E3 1220 인데도… 꽤나 오래걸린다. 빌드하는 동안 CPU 사용률이 30~50% 정도를 왔다갔다한다. 대략 10~15분 정도 걸리는 것 같다.

cc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/token_ids.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/wave_config_constant.o
common.mkdir bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer
common.mkdir bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer/re2clex
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer/re2clex/aq.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer/re2clex/cpp_re.o
gcc.archive bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/libboost_wave.a
common.copy stage/lib/libboost_wave.a
...updated 1084 targets...
The Boost C++ Libraries were successfully built!
The following directory should be added to compiler include paths:
/backup/program/boost_1_54_0
The following directory should be added to linker library paths:
/backup/program/boost_1_54_0/stage/lib
[root@83rpm boost_1_54_0]#

한참 기다리면 위와 같은 메시지가 나온다. 부스트 라이브러리 빌드에 성공했다는 메시지와 컴파일러에서 인클루드할 경로, 라이브러리 경로를 알려주는 메시지이다.

이것으로 끝.

윈도우에서 빌드할 때는 여러가지 옵션을 넣고 한 것 같은데 리눅스에서는 너무 쉽게 끝나서 뭔가 이상하다. 혹시나 이 빌드 방법이 잘못되었다면 다음번에 수정해 나가도록 한다.

boost::thread_group

부스트의 쓰레드 그룹을 사용하기 위한 코드

출처 : http://nerv2000.tistory.com/76

#include "boost/thread.hpp"

class threadFunc
{
    int m_a;
public:
    threadFunc( int a )
    {
        m_a = a;
    }

    void operator()()
    {
        printf("[%d]일단 들어왔네!!! [%d]n", boost::this_thread::get_id(), m_a );

        Sleep(5000);

        printf("[%d] 끝났네 [%d]n", boost::this_thread::get_id(), m_a );
    }
};

int main()
{
    boost::thread_group tg;

    tg.create_thread( threadFunc(1) );                        // 1번 스래드 생성
    tg.add_thread(new boost::thread( threadFunc(2) ) );        // 2번 스래드 생성
    tg.add_thread(new boost::thread( threadFunc(3) ) );        // 3번 스래드 생성

    //모든 스래드가 종료 될때까지 대기
    tg.join_all();

    return 0;
}

Boost alt_sstream_impl.hpp warning C4819 에러 해결 방법

열심히 작업하고 빌드를 하는데 계속 warning 메시지가 떴다.

내용은

1>C:Libraryboost_1_51_0boost/format/alt_sstream_impl.hpp : warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오. (..srcbusinessservicepbbmcacheMemberInfoManager.cpp)

빌드가 안되는 것도 아니고 프로그램에 오류가 있는 것도 아니지만 뭔가해서 이 메시지를 찾아보았다.

저 메시지를 더블클릭하면 부스트의 alt_sstream_impl.hpp 파일이 열리면서 파일 인코딩에 문제가 있다고 팝업창이 뜬다. 이 파일을 열고 한참 봤지만 문제가 없어보인다. 그냥 인코딩변환해버리면 저 에러메시지가 사라지겠지만 부스트 파일을 건드리는건 여간 기분이 찜찜한지라 구글에서 검색시작.

StackOverflow에서 다음의 글을 찾았다.

http://stackoverflow.com/questions/10501634/warning-c4819-how-to-find-the-character-that-has-to-be-saved-in-unicode

글 내용을 읽어보니 alt_sstream_impl.hpp 파일에 176번 라인의 주석이 문제였다. 에휴…

해결방법은 Notepad++로 이 파일을 열고 176번 라인의 주석을 모두 지워버리고 다시 빌드해보면 위 오류 메시지가 없어진다.