반응형
개요
TCP 소켓으로 원격 어플리케이션과 통신을 시작하려면 먼저 논리적 연결을 수립해야 한다.
TCP 프로토콜의 연결 수립이란 두 프로그램 사이에서 메시지를 주고 받는것을 의미한다.
이것이 성공해야 두 프로그램이 연결된 것으로 간주할 수 있고, 통신을 할 수 있는 준비가 끝난다.
연결 수립 과정을 간단하게 설명하면 다음과 같다.
- 서버 프로그램과 통신하기 원하는 클라이언트 프로그램이 존재
- 클라이언트가 능동 소켓을 생성하고 연 후 connect() 명령을 내림
- 이때 종료점 객체를 통해 원하는 대상 서버프로그램을 명시함
- 네트워크 연결을 통해 연결 수립 요청 메시지를 서버 프로그램으로 전송
- 요청을 받은 서버 프로그램은 자기가 사용할 능동 소켓을 만듦
- 클라이언트와 연결 됐음을 표시하고 이를 클라이언트에 알림(ACK 전달)
- 클라이언트가 서버의 메시지를 받으면 이를 표시하고 서버측에 메시지를 보냄
- 서버측에서도 메시지를 성공적으로 받았다면 연결이 수립되었다고 간주함
연결된 두 소켓 사이에서는 1:1 통신 모델이 적용된다.
소켓 A와 B가 연결되었다면, 다른 소켓 C와 통신할 수 없다.
만약 소켓 C와 통신을 원한다면 기존의 통신을 끊고 소켓 C와 다시 연결해야 한다.
현재는 스레드 및 동기 메서드를 사용하고 있기 때문이다.
클라이언트 소켓 연결(IP)
- 대상 서버 프로그램의 IP 주소와 프로토콜 포트 번호를 알아낸다.
- 위에서 알아낸 IP 주소와 프로토콜 포트 번호로 종료점을 생성한다.
- 능동 소켓을 만들고 연다.
- 2번에서 생성한 종료점 객체를 인자로 전달하며, 소켓의 connect() 메서드를 호출한다.
- 메서드가 성공적으로 리턴값을 반환했다면 이제 서버와 통신할 수 있다.
#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 이름과 프로토콜 포트 번호로 표시된 서버 프로그램에 소켓 연결하는 방법은 다음과 같다.
- 서버프로그램이 실행되고 있는 호스트의 DNS 이름과 서버의 포트 번호를 문자열로 초기화 한다.
- resolver 클래스를 사용해 DNS 이름을 IP 주소로 해석한다.
- 능동 소켓을 생성한다.
- 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 |