개요
비동기 연산을 시작하도록 한 후에 아직 완료되지 않았지만 종료하고 싶을 수가 있다.
더 이상 해당 작업이 필요 없거나, 도중에 다른 방향으로 연산을 하고 싶을 때 등등
클라이언트 입장에선 시작은 했지만 아직 끝나지 않은 연산을 종료할 수 있다면 좋은 기능이다.
네트워크 통신 연산은 예측하지 못할 정도로 긴 시간이 걸릴 수도 있으므로 취소하는 기능을 제공하는 것은 중요하다.
cancel()
일단 코드를 먼저 작성하고 리뷰를 진행한다.
#include <boost/asio.hpp>
#include <iostream>
#include <thread>
using namespace boost;
int main()
{
std::string raw_ip_address = "127.0.0.1";
unsigned short port_num = 3333;
try {
asio::ip::tcp::endpoint ep(asio::ip::address::from_string(raw_ip_address), port_num);
// 최신 Boost에서는 io_service 대신 io_context 사용
asio::io_context ios;
std::shared_ptr<asio::ip::tcp::socket> sock(
new asio::ip::tcp::socket(ios, ep.protocol()));
// 비동기 연결 요청
sock->async_connect(ep,
[sock](const boost::system::error_code& ec) // 콜백 함수를 람다로 넣었음
{
if (ec.value() != 0) {
if (ec == asio::error::operation_aborted) {
std::cout << "Operation cancelled!" << std::endl;
}
else {
std::cout << "Error occured! "
<< "Error code = " << ec.value()
<< ". Message: " << ec.message() << std::endl;
}
return;
}
// 연결이 완료되었을 때, 소켓을 사용하여 원격 애플리케이션과 통신할 수 있음
});
// 비동기 작업이 완료되면 콜백을 실행할 worker_thread 생성
std::thread worker_thread([&ios]() {
try {
ios.run(); // 비동기 작업 처리
}
catch (system::system_error& e) {
std::cout << "Error occured! "
<< "Error code = " << e.code()
<< ". Message: " << e.what() << std::endl;
}
});
// 임의로 지연을 주기 위해 2초 대기
std::this_thread::sleep_for(std::chrono::seconds(2));
// 비동기 작업 취소
sock->cancel();
// worker_thread가 종료될 때까지 대기
worker_thread.join();
}
catch (system::system_error& e) {
std::cout << "Error occured! Error code = " << e.code()
<< ". Message: " << e.what() << std::endl;
return e.code().value();
}
return 0;
}
늘 그랬듯 서버의 IP 주소와 포트 번호를 안다고 가정하고 종료점 및 소켓을 생성하여 비동기 연결 요청을 한다.
async_connect 메서드를 통해 생성한 종료점 ep에 비동기 연결 요청을 하는 것이다.
이때 뒤에 연결 실패 시 ec를 출력하는 부분은 람다함수로 콜백 함수를 구현한 것이다.
만약 해당 메서드가 반복하여 사용될 것 같다면 별도의 함수로 정의해 주면 된다.
연결이 완료되었다면 이제 소켓을 사용해 서버와 통신할 수 있다.
여러가지 원하는 비동기 작업 후 콜백을 실행하기 위해 쓰레드를 사용해 준다.
스레드를 생성해 주고 ios.run()을 실행해 준다, 이때 에러가 발생해 준다면 catch문이 실행된다.
스레드를 만들고 난 후 중심 스레드는 2초간 대기 상태에 들어간다, 그 동안 연결 연산이 진행된다.
sleep을 해주지 않는다면 비동기 연산 작업이 시작되고 곧 바로 cancel메서드가 호출되면 연산 자체가 되지 않는다.
현재 예제로는 비동기 연산을 시작하고 2초 이상 걸리는 작업이 있다면 취소하는 것으로 볼 수 있다.
ios.run()을 스레드로 처리하는 이유는 ios.run()은 블로킹 함수이기 때문이다.
해당 함수가 호출되면 내부 이벤트가 모두 종료될 때 까지 다른 작업을 처리할 수 없다.
따라서 비동기 작업을 처리하며 다른 코드가 계속 실행되게 하려면 ios.run()을 별도의 쓰레드에서 실행시켜야 한다.
위 처럼 비동기 연결 중 cancel메서드를 사용하면 사용자가 원하는 시점에 비동기 작업을 종료할 수 있다.
'네트워크 통신 > Boost' 카테고리의 다른 글
Boost.asio 클라이언트 개요 (1) | 2024.11.14 |
---|---|
Boost.asio I/O 소켓 종료하기와 닫기 (1) | 2024.11.14 |
Boost.asio I/O TCP 소켓 비동기적 읽기 (1) | 2024.11.14 |
Boost.asio I/O TCP 소켓 비동기적 쓰기 (0) | 2024.11.14 |
Boost.asio I/O TCP 소켓 동기적 읽기 (0) | 2024.11.08 |