버퍼 (Buffers)
기본적으로, I/O는 버퍼라고 불리는 메모리 인접 영역과 데이터를 주고받는 것을 포함한다. 이러한 버퍼는 포인터와 크기(바이트)로 구성된 튜플로 단순하게 표현할 수 있다. 효율적인 네트워크 응용프로그램을 개발을 허용하기 위해 Boost.Asio는 Scatter-Gather(분산-수집) 작업의 지원을 포함한다. 이러한 작업은 하나 이상의 버퍼를 포함한다:
- Scatter 읽기는 데이터를 여러 버퍼로 수신한다.
- Gather 쓰기는 여러 버퍼를 전송한다.
※ Scatter-Gather는 분산-수집으로 번역이 가능하지만, 글의 전체적인 이해를 위해 영문 그대로 사용한다.
그러므로 버퍼 컬렉션을 표현하려면 추상화가 필요하다. Boost.Asio에서 사용되는 접근 방식은 단일 버퍼를 나타내는 유형(실제로 두 가지 유형)을 정의하는 것이다. 이는 Scstter-Gather 작업에 전달될 수 있는 컨테이너에 저장할 수 있다.
버퍼를 포인터와 크기(바이트)로 지정하는 것 외에, Boost.Asio는 수정 가능 메모리(뮤터블:mutable이라 부른다)와 수정 불가능 메모리(후자는 const 한정 변수를 위한 저장소에서 생성된다)를 구분한다. 따라서 두 가지 유형은 다음과 같이 정의될 수 있다:
typedef std::pair<void*, std::size_t> mutable_buffer; typedef std::pair<const void*, std::size_t> const_buffer;
여기서 mutable_buffer는 const_buffer로 변환 가능하지만, 반대 방향의 변환은 유효하지 않다.
그러나 Boost.Asio는 위의 정의를 그래로 사용하지 않고, 대신 mutable_buffer와 const_buffer라는 두 클래스를 정의한다. 이들의 목표는 인접 메모리의 불투명한 표현을 제공하는 것이다. 여기서:
- 유형은 변환에서 std::pair처럼 작동한다. 즉, mutable_buffer는 const_buffer로 변환 가능하지만, 반대 변환은 허용되지 않는다.
- 버퍼 오버런(overruns)에 대한 보호 기능이 있다. 버퍼 인스턴스가 지정되면, 사용자는 동일한 메모리 범위 또는 그 하위 범위를 나타내는 다른 버퍼만 생성할 수 있다. 추가적인 안전성을 제공하기 위해, 라이브러리는 배열, POD 요소의 boost::array 또는 std::vector 또는 std::string에서 버퍼 크기를 자동으로 결정하는 메커니즘을 포함하고 있다.
- 기본 메모리는 data() 멤버 함수를 사용하여 명시적으로 접근한다. 일반적인 응용프로그램에서 이 작업을 수행할 필요가 없지만, 기본 운영 체제 함수에 원시(raw) 메모리를 전달하는 라이브러리 구현의 경우에는 필요하다.
마지막으로, 컨테이너에 버퍼 개체를 넣어서 scatter-gather 작업(read() 또는 write() 같은)에 여러 버퍼를 전달할 수 있다. MutableBufferSequence와 ConstBufferSequence 개념은 std::vector, std::list, std::array 또는 boost::array와 같은 컨테이너를 사용할 수 있도록 정의되었다.
Iostreams(Boost.Iosteams)와 통합을 위한 streambuf
boost::asio::basic_streambuf 클래스는 std::basic_streambuf에서 파생되어 입력 시퀀스와 출력 시퀀스를 일부 문자 배열 유형(임의 값을 저장하는 요소)의 하나 이상의 개체와 연결한다. 이러한 문자 배열 개체는 streambuf 개체의 내부에 있지만, 배열 요소에 대한 직접 접근이 제공되어 소켓의 송수신 작업과 같은 I/O 작업에서 사용할 수 있다:
- streambuf의 입력 시퀀스는 data() 멤버 함수로 접근할 수 있다. 이 함수의 반환 유형은 ConstBufferSequence 요건을 충족한다.
- streambuf의 출력 시퀀스는 prepare() 멤버 함수로 접근할 수 있다. 이 함수의 반환 유형은 MutableBufferSequence 요건을 충족한다.
- commit() 멤버 함수를 호출하여 출력 시퀀스의 앞쪽에서 입력 시퀀스의 뒤쪽으로 데이터를 전송된다.
- consume() 멤버 함수를 호출하여 입력 시퀀스의 앞쪽에서 데이터를 제거한다.
streambuf 생성자는 입출력 시퀀스의 최대 합계 크기를 지정하는 size_t 인수를 받아들인다. 작업이 성공할 경우, 이 제한을 초과하여 내부 데이터를 증가시키는 모든 작업은 std::length_error 예외를 발생시킨다.
버퍼 시퀀스의 바이트 단위 순회 (Bytewise Traversal of Buffer Sequences)
buffer_iterator<> 클래스 템플릿은 버퍼 시퀀스(즉 MutableBufferSequence 또는 ConstBufferSequence 요건을 충족하는 유형)를 바이트의 연속적인 배열인 것처럼 순회할 수 있다. buffers_begin()과 buffers_end()라는 도우미 함수도 제공되며, 여기서 buffers_iterator<> 템플릿 파라미터가 자동으로 추론된다.
예를 들어, 소켓에서 한 라인을 std::string으로 읽으려면 다음과 같이 작성할 수 있다:
boost::asio::streambuf sb; ... std::size_t n = boost::asio::read_until(sock, sb, '\n'); boost::asio::streambuf::const_buffers_type bufs = sb.data(); std::string line( boost::asio::buffers_begin(bufs), boost::asio::buffers_begin(bufs) + n);
버퍼 디버깅
Microsoft Visual C++ 8.0 이상 버전과 함께 제공되는 일부 표준 라이브러리 구현에 iterator 디버깅이라는 기능을 제공한다. 이것이 의미하는 것은 iterator의 유효성을 런타임에 확인한다는 것이다. 프로그램이 무효화된 iterator를 사용하려고 하면 어서션(assertion)이 트리거된다. 예를 들면 다음과 같다:
std::vector<int> v(1) std::vector<int>::iterator i = v.begin(); v.clear(); // invalidates iterators *i = 0; // assertion!
Boost.Asio는 이 기능을 활용하여 버퍼 디버깅을 추가한다. 다음 코드를 고려한다:
void dont_do_this() { std::string msg = "Hello, world!"; boost::asio::async_write(sock, boost::asio::buffer(msg), my_handler); }
비동기 읽기나 쓰기를 호출할 때, 완료 핸들러가 호출될 때까지 작업에 대한 버퍼가 유효한지 확인해야 한다. 위의 예에서, 버퍼는 std::string 변수 msg이다. 이 변수는 스택에 있으므로 비동기 작업이 완료되기 전에 범위(scope)를 벗어난다. 운이 좋으면 응용프로그램이 중단(crash)되지만, 임의의 오류가 발생할 가능성이 더 높다.
버퍼 디버깅이 활성화된 경우, Boost.Asio는 비동기 작업이 완료될 때까지 iterator를 문자열에 저장한 다음, 유효성을 확인하기 위해 역참조를 한다. 위의 예에서 Boost.Asio가 완료 핸들러를 호출하기 직전에 어서션(assertion) 실패를 볼 것이다.
이 기능은 _GLIBCXX_DEBUG가 정의된 경우 Microsoft Visual Studio 8.0 이상 및 GCC에서 자동으로 사용할 수 있다. 이 검사에는 성능 비용이 있으므로 버퍼 디버깅은 디버그 빌드에서만 사용할 수 있다. 다른 컴파일러의 경우 BOOST_ASIO_ENABLE_BUFFER_DEBUGGING를 정의하여 사용할 수 있고, BOOST_ASIO_DISABLE_BUFFER_DEBUGGING 정의하여 명시적으로 비활성화할 수도 있다.
※ Microsoft Visual C++ 8.0와 Microsoft Visual Studio 8.0는 Microsoft Visual Studio 2005 이상의 버전을 지칭하는 것 같다.
더 보기
buffer, buffers_begin, buffers_end, buffers_iterator, const_buffer, const_buffers_1, mutable_buffer, mutable_buffers_1, streambuf, ConstBufferSequence, MutableBufferSequence, buffers example (C++03), buffers example (c++11).
'Boost C++ Libraries > Boost.Asio' 카테고리의 다른 글
Boost.Asio 개요 - 핵심 개념 및 기능 - Reactor 스타일 작업 (0) | 2020.12.08 |
---|---|
Boost.Asio 개요 - 핵심 개념 및 기능 - 스트림, 짧은 읽기와 짧은 쓰기 (0) | 2020.12.08 |
Boost.Asio 개요 - 핵심 개념 및 기능 - 스트랜드: 명시적 잠금없이 스레드 사용 (0) | 2020.12.07 |
Boost.Asio 개요 - 핵심 개념 및 기능 - 스레드와 Boost.Asio (0) | 2020.12.07 |
Boost.Asio 개요 - 핵심 개념 및 기능 - Proactor 디자인 패턴: 스레드 없는 동시 실행 (0) | 2020.12.06 |