네트워크 통신/Boost

Boost.asio 소켓 연결 요청

마달랭 2024. 11. 7. 23:21
반응형

개요

TCP 소켓으로 원격 어플리케이션과 통신을 시작하려면 먼저 논리적 연결을 수립해야 한다.

TCP 프로토콜의 연결 수립이란 두 프로그램 사이에서 메시지를 주고 받는것을 의미한다.

이것이 성공해야 두 프로그램이 연결된 것으로 간주할 수 있고, 통신을 할 수 있는 준비가 끝난다.

 

연결 수립 과정을 간단하게 설명하면 다음과 같다.

  1. 서버 프로그램과 통신하기 원하는 클라이언트 프로그램이 존재
  2. 클라이언트가 능동 소켓을 생성하고 연 후 connect() 명령을 내림
  3. 이때 종료점 객체를 통해 원하는 대상 서버프로그램을 명시함
  4. 네트워크 연결을 통해 연결 수립 요청 메시지를 서버 프로그램으로 전송
  5. 요청을 받은 서버 프로그램은 자기가 사용할 능동 소켓을 만듦
  6. 클라이언트와 연결 됐음을 표시하고 이를 클라이언트에 알림(ACK 전달)
  7. 클라이언트가 서버의 메시지를 받으면 이를 표시하고 서버측에 메시지를 보냄
  8. 서버측에서도 메시지를 성공적으로 받았다면 연결이 수립되었다고 간주함

연결된 두 소켓 사이에서는 1:1 통신 모델이 적용된다.

소켓 A와 B가 연결되었다면, 다른 소켓 C와 통신할 수 없다.

만약 소켓 C와 통신을 원한다면 기존의 통신을 끊고 소켓 C와 다시 연결해야 한다.

현재는 스레드 및 동기 메서드를 사용하고 있기 때문이다.

 

 

클라이언트 소켓 연결(IP)

  1. 대상 서버 프로그램의 IP 주소와 프로토콜 포트 번호를 알아낸다.
  2. 위에서 알아낸 IP 주소와 프로토콜 포트 번호로 종료점을 생성한다.
  3. 능동 소켓을 만들고 연다.
  4. 2번에서 생성한 종료점 객체를 인자로 전달하며, 소켓의 connect() 메서드를 호출한다.
  5. 메서드가 성공적으로 리턴값을 반환했다면 이제 서버와 통신할 수 있다.
#include <boost/asio.hpp>
#include <iostream>

using namespace boost;

int main()
{
	// Step 1. 서버의 IP 및 포트 번호를 안다고 가정
	std::string raw_ip_address = "127.0.0.1";
	unsigned short port_num = 3333;

	try {
		// Step 2. IP와 포트 번호를 통해 종료점 생성
		asio::ip::tcp::endpoint
			ep(asio::ip::address::from_string(raw_ip_address),
				port_num);

		asio::io_service ios;

		// Step 3. io_service 인스턴스와 종료점을 통해 소켓 생성
		asio::ip::tcp::socket sock(ios, ep.protocol());

		// Step 4. 서버에 연결 요청
		sock.connect(ep);
	}
	// 예외가 발생하지 않았다면 이제 서버와 통신 가능
	catch (system::system_error& e) {
		std::cout << "Error occured! Error code = " << e.code()
			<< ". Message: " << e.what();

		return e.code().value();
	}

	return 0;
}

 

 

클라이언트 소켓 연결(DNS)

DNS 이름과 프로토콜 포트 번호로 표시된 서버 프로그램에 소켓 연결하는 방법은 다음과 같다.

 

  1. 서버프로그램이 실행되고 있는 호스트의 DNS 이름과 서버의 포트 번호를 문자열로 초기화 한다.
  2. resolver 클래스를 사용해 DNS 이름을 IP 주소로 해석한다.
  3. 능동 소켓을 생성한다.
  4. connect() 함수를 호출하며 2단계에서 얻은 해석된 IP 주소를 인자로 전달한다.
#include <boost/asio.hpp>
#include <iostream>

using namespace boost;

int main()
{
	// Step1. 연결하고자 하는 서버 프로그램의 DNS 이름과 포트 번호 초기화
	std::string host = "samplehost.book";
	std::string port_num = "3333";

	// io_service 인스턴스 생성
	asio::io_service ios;

	// resolver에 전달할 질의 작성
	asio::ip::tcp::resolver::query resolver_query(host, port_num,
		asio::ip::tcp::resolver::query::numeric_service);

	// resolver 생성
	asio::ip::tcp::resolver resolver(ios);

	try {
		// Step 2. DNS 이름 해석
		asio::ip::tcp::resolver::iterator it =
			resolver.resolve(resolver_query);

		// Step 3. 소켓 생성
		asio::ip::tcp::socket sock(ios);

		// Step 4. 성공적으로 연결될 때 까지 반복자를 순환
		// 어떤 ep와도 연결할 수 없거나 오류 발생 시 예외 처리
		asio::connect(sock, it);

		// catch문이 실행되지 않았다면 이제부터 서버 통신 가능
	}
	catch (system::system_error& e) {
		std::cout << "Error occured! Error code = " << e.code()
			<< ". Message: " << e.what();

		return e.code().value();
	}

	return 0;
}

 

 

728x90
반응형

'네트워크 통신 > Boost' 카테고리의 다른 글

Boost.asio I/O 연산  (0) 2024.11.08
Boost.asio 소켓 연결 수락  (0) 2024.11.07
Boost.asio 소켓 바인딩  (0) 2024.11.07
Boost.asio DNS 이름 해석하기  (1) 2024.11.07
Boost.asio 능동/수동 소켓 만들기  (0) 2024.11.07