검색결과 리스트
글
C++에서 Boost ASIO를 사용하여 TCP 동기화(Blocked) 통신 프로그래밍
지난 포스팅에서 C++에서 제공하는 Boost 라이브러리의 통신 라이브러리인 ASIO를 사용하여 비동기 통신 프로그래밍을 하는 방법에 대해 소개를 하였던 적이 있었습니다.
C++에서 Boost ASIO를 사용하여 TCP 비동기(Unblocked) 통신 프로그래밍
서버-클라이언트 통신 시스템을 구축하던 도중 Java에서 사용하던 객체 통신 프로그래밍 방식이 상당히 편했던 기억이 있어 이를 C++에서도 편하게 사용할 수 있는 방법을 찾았던 것이어서 이를 정리하였던 글이었는데 생각보다 많은 분들께서 도움을 받으셨다는 답변을 받았습니다.
그래서 이번에는 ASIO 통신 프로그래밍에서 다룰 만한 내용으로 동기화(Synchronization, Blocked) 프로그래밍 방식에 대해 이야기 해보고자 합니다.
위 그림은 ASIO 프로그래밍의 동기화 통신 방식의 흐름도를 나타낸 것입니다. 이전 포스팅에서 다루었던 비동기화 통신 방식과는 달리 동기화 통신은 상대로부터 response를 대기하는 과정이 추가됩니다.
비동기 모드의 경우 Handler를 등록해두면 response의 수신 여부와 관계 없이 서버는 프로그램의 동작을 멈추지 않고 별개의 동작을 수행할 수 있습니다. 반면 동기화 통신의 경우 상대방의 response가 들어오고 나서 동작하는 방식이므로 서로가 통신이 확인이 되었는지의 여부를 확인할 수 있다는 장점이 있습니다.
먼저 프로세스는 socket에 자신의 IP 정보를 기록한 후 이를 io_service(Boost 1.66 버전 이후는 io_context)를 통해 운영체제 커널에 정보를 등록합니다. 이후 운영체제가 다른 컴퓨터로부터 응답을 수신하게 되면 이를 프로세스의 socket에게 전달하고 프로세스는 전달 받은 정보를 가공하는 방식으로 통신이 이루어집니다.
자세한 내용은 아래의 소스코드를 통해 알아보도록 하겠습니다.
프로그램을 실행하기에 앞서 자신의 컴퓨터에 Boost 라이브러리를 설치합니다. Ubuntu를 기준으로 다음과 같이 실행합니다.
$ sudo apt install libboost-all-dev
이제 어러분의 컴퓨터에는 Boost 라이브러리가 설치되었습니다. 다음으로 아래의 소스코드를 작성해줍니다.
sync_server.cc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #include<cstdlib> #include<iostream> #include<boost/asio.hpp> using namespace std; using boost::asio::ip::tcp; class session { public: session(tcp::socket& sock) //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용 //session(boost::asio::io_context& io_service) : socket_(sock){ start(); } void start(){ try{ while(1){ boost::system::error_code error; size_t length = socket_.read_some(boost::asio::buffer(data_), error); if(error == boost::asio::error::eof){ //클라이언트로 부터 정보를 모두 받았으므로 종료한다. break; }else if(error){ throw boost::system::system_error(error); } cout << "Message from client: " << data_ << endl; boost::asio::write(socket_, boost::asio::buffer(data_, length)); } }catch(exception& e){ cerr << "Exception in server: " << e.what() << endl; } } tcp::socket& socket(){return socket_;} private: tcp::socket& socket_; enum { max_length = 1024 }; char data_[max_length]; }; class server { public: server(boost::asio::io_service& io_service, short port) //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용 //server(boost::asio::io_context& io_service, short port) : io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) { while(1){ //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용 //new session(acceptor_.accept()); //sever의 소켓 생성 tcp::socket sock(io_service); //client로부터 접속 대기 acceptor_.accept(sock); new session(sock); } } private: boost::asio::io_service& io_service_; //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용 //boost::asio::io_context &io_service_; tcp::acceptor acceptor_; }; int main(int argc, char* argv[]){ try{ if(argc != 2){ cerr << "Usage: server <port>" << endl; return 1; } boost::asio::io_service io_service; //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용 //boost::asio::io_context io_service; server s(io_service, atoi(argv[1])); }catch(exception& e){ cerr << "Exception: " << e.what() << endl; } return 0; } | cs |
sync_client.cc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #include<cstdlib> #include<iostream> #include<boost/asio.hpp> using boost::asio::ip::tcp; using namespace std; class client { public: client(boost::asio::io_service& io_service, //client(boost::asio::io_context& io_service, const string& host, const string& port) : socket_(io_service) { tcp::resolver resolver(io_service); //서버에 접속을 시도한다. boost::asio::connect(socket_, resolver.resolve({host, port})); string msg = "Hello, world!"; size_t msg_length = msg.length(); //서버로 데이터를 전송 boost::asio::write(socket_, boost::asio::buffer(msg, msg_length)); char reply[max_length]; //서버로부터 데이터를 수신 size_t reply_length = boost::asio::read(socket_, boost::asio::buffer(reply, msg_length)); cout << "Reply is: " << reply << endl; } private: tcp::socket socket_; enum { max_length = 1024 }; }; int main(int argc, char* argv[]){ try{ if(argc != 3){ cerr << "Usage: client <host> <port>" << endl; return 1; } //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용 //boost::asio::io_context &io_service; boost::asio::io_service io_service; client c(io_service, argv[1], argv[2]); }catch(exception& e){ cerr<<"Exception: " << e.what() << endl; } return 0; } | cs |
CMakeLists.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | cmake_minimum_required(VERSION 3.0) add_compile_options(-std=c++11) project(asio_sync) find_package(Boost REQUIRED system) find_package(Threads) include_directories(${Boost_INCLUDE_DIR}) add_executable(client sync_client.cc ) add_executable(server sync_server.cc ) target_link_libraries(client ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) target_link_libraries(server ${Boost_LIBRARIES} ) | cs |
Linux 환경에서 다음과 같이 프로그램을 컴파일합니다.
$ mkdir build
$ cd build
$ cmake ..
$ make
이제 우리가 만든 프로그램을 실행하여봅니다.
Server
1 2 | $ ./server 2222 Message from client: Hello, world! | cs |
Client
1 2 | $./client 127.0.0.1 2222 Reply is: Hello, world! | cs |
축하합니다! 이제 여러분들도 Boost 라이브러리의 ASIO를 사용하여 동기화 통신 프로그래밍을 만들 수 있게 되었습니다!
'공대생의 팁' 카테고리의 다른 글
| Canon MG2990 시리즈 USB 연결 설치방법 (0) | 2019.10.11 |
|---|---|
| Windows 10 Internet Explorer 11 에서 Adobe flash가 실행되지 않을때 해결방법 (1) | 2019.08.26 |
| 리눅스(우분투)에서 USB가 동작하지 않을 때 수동으로 연결하기(Failed to open the USB device!) (0) | 2019.07.05 |
| C++에서 Graphviz로 그래프 이미지 그리기 (0) | 2019.07.04 |
| Extreme Learning Machine(극학습기계) (0) | 2019.05.15 |
설정
트랙백
댓글
글
무더운 여름날 김유정역 강촌레일파크 [2019.07.17]
평소에 레일바이크를 타보고 싶었던 적이 있었는데 마침 친구와 단둘이 여행을 할 수 있는 기회가 생겨 친구와 함께 레일바이크에 도전해 보게 되었습니다. 마침 춘천 인근에 있는 김유정역에 레일바이크가 있다는 이야기를 듣고 찾아가 보았습니다.
레일바이크의 시작점에서..
자전거 타듯이 페달만 열심히 저어주면 됩니다.
레일바이크 옆으로 펼쳐지는 풍경이 정말 대단합니다.
레일바이크 종착지에는 이렇게 쉼터가 마련되어 있습니다.
여기서 바라보는 풍경도 상당히 좋더군요.
종착지에서 강촌역까지는 특수열차를 타고 이동합니다.
열차에 올라서 바라보는 풍경도 꽤 장관입니다.
무궁화호를 타고서는 보기 힘든 광경들이 이렇게 지붕 없는 객차에서는 새로운 풍경으로 비쳐집니다.
어느덧 강촌역 인근에 도착
바닥을 보니 생각보다 높은 위치더군요
오랜만에 본 옛 강촌역의 모습
비록 열차는 정차하지 않지만 그 당시의 모습만은 고이 간직하고 있군요.
또오리 강촌!
'좌충우돌 여행기 > 국내여행' 카테고리의 다른 글
| 하나된 열정, 뜨거운 열정! 평창 동계올림픽(5) - 1년후 이야기 [2019.08.20] (0) | 2019.08.22 |
|---|---|
| 평창올림픽의 열정을 다시 한 번, 평창남북평화영화제 [2019.08.19] (0) | 2019.08.21 |
| 바다가 보이는 간이역 월내역에서 기차가 서던 마지막날 [2019.07.14] (0) | 2019.07.16 |
| 철길도 이사를 간다? 덕하역 이설 전날 풍경(2) [2019.06,16] (0) | 2019.06.21 |
| 철길도 이사를 간다? 덕하역 이설 전날 풍경(1) [2019.06.16] (0) | 2019.06.19 |
설정
트랙백
댓글
글
바다가 보이는 간이역 월내역에서 기차가 서던 마지막날 [2019.07.14]
지난 달에 동해선 덕하역을 다녀간지 한 달만에 동해선 부산 구간은 또 한번의 격변기를 맞이하게 되었습니다. 오늘로써 일광역부터 태화강역까지 기존의 철길에서 새로운 철길로 이사를 가게 되면서 이제는 지금까지 기차가 지나다니던 그 모습들은 역사속으로 사라졌기 때문이지요.
오늘은 그러한 역사속 모습을 마지막까지 간직하고 있던 월내역 인근을 돌아다녀 보았습니다. 지금의 월내역은 기존역 역을 철거하고 임시로 세워져 있지만 여전히 무궁화호가 정차하던 역이었는데 오늘을 끝으로 더이상 무궁화호는 정차하지 않게 됩니다. 다만 앞으로 이설될 새로운 월내역은 고가역이 되어 바다가 훨씬 더 잘 보일 것으로 보입니다!
지난달에 방문하였던 덕하역 인근 구간을 지날 때 였는데
놀랍게도 이번에는 새로 이설한 고가 구간을 통과하는 겁니다!
아래의 이설 전 고가는 벌써부터 철거에 들어가 있더군요.
혹시 이설 바로 전날 이 곳의 모습이 궁금하시다면 아래의 포스팅을 확인해주세요!
철길도 이사를 간다? 덕하역 이설 전날 풍경(2) [2019.06,16]
5개월만에 다시 월내역에 방문하는군요. 승강장에는 벌써 잡초가 무성합니다.
승강장 너머 고가철로 끝에는 새로운 월내역이 건설중입니다.
아직 광역전철이 개통하기까지 1년 넘게 남았는데 벌써 폐쇄된다니
새로운 월내역과 기존의 철길 모습입니다.
역 내에는 굴삭기가 개통 준비를 서두르고 있습니다.
남창역 방향을 향하여 찍은 모습입니다. 아마 내일이면 더이상 열차는 다니지 않습니다.
고가와 건널목.. 공존할 수 없는 관계일까요?
저 멀리 월내역의 임시승강장이 보입니다.
기존 철교와 새로 지어지고 있는 철교 사이의 자전거도로입니다.
한적하게 낚시를 하시는 분이 보입니다.
옛 철교 뒤로 내일부터 새로 개통될 철교가 보입니다.
이런 구도 쉽지 않은데!
넓디넓은 4차선 도로에 건널목 하나가 떡하니 서 있습니다.
원래 여기는 2차선 작은 도로였는데 인근에 아파트가 건설되면서 4차선으로 확장되었습니다.
아마도 이 철길이 이설될 예정이라서 불편해도 미리 길을 확장해둔 듯 합니다.
그 덕에 기존의 관리원님들이 계시던 건물을 허러내고 저렇게 컨테이너로 건물이 대체된 상황입니다.
아마 이보다 더 큰 길에 건널목이 있던게 9년전 경춘선 이설 직전 화랑대역 인근 건널목이었을겁니다.
그땐 아마 6차선이었을겁니다.
어느덧 건널목은 우렁차게 울리기 시작하고
도로위를 부지런히 다니던 차량들이 잠시 정차합니다.
장안2건널목의 마지막날에도 이렇게 기차는 순식간에 지나갑니다.
이제 관리원님들께서도 내일부터는 이 곳에서 더이상 볼 수 없게 됩니다.
다시 월내역을 돌아옵니다.
아까 고가 위에 보았던 굴삭기가 여전히 분주히 작업을 진행하고 있습니다.
내일부터는 이 출입구도 폐쇄되겠지요
앞으로 이 곳에 오기 위해서는 좌천역에서 운행하는 대체 버스를 타고 와야 할 듯 합니다.
마지막날인 오늘도 승객들은 이 곳에서 열차를 기다립니다.
지금은 사라졌지만 광역전철이 개통하면 서생역에도 열차가 정차하게 됩니다.
어느덧 열차는 월내역으로 들어옵니다.
이 역의 마지막을 아는지 탑승객들이 기차를 바라보며 셀카를 찍습니다.
이제 열차에 탑승합니다.
방금전에 들렀던 곳을 이렇게 사진으로 님기기는 처음입니다.
방금 뵙고 갔던 관리원님도 마지막날까지 열심히 일을 하고 계시는군요.
덕하역 인근에 이설된 고가 인근의 모습입니다.
저 곳에서 이 열차가 달리는 임시철교를 만들고 있던게 떠오르는군요.
과연 다음 여행지는 어디가 될까요?
'좌충우돌 여행기 > 국내여행' 카테고리의 다른 글
| 평창올림픽의 열정을 다시 한 번, 평창남북평화영화제 [2019.08.19] (0) | 2019.08.21 |
|---|---|
| 무더운 여름날 김유정역 강촌레일파크 [2019.07.17] (0) | 2019.07.20 |
| 철길도 이사를 간다? 덕하역 이설 전날 풍경(2) [2019.06,16] (0) | 2019.06.21 |
| 철길도 이사를 간다? 덕하역 이설 전날 풍경(1) [2019.06.16] (0) | 2019.06.19 |
| 도심속 작은 간이역 사상역의 흔적들 [2019.06.16] (2) | 2019.06.18 |