C++의 소켓 프로그래밍

C Ui Sokes Peulogeulaeming



소켓 프로그래밍은 컴퓨터 네트워킹 분야에서 중요한 주제가 되었습니다. 중단 없이 서로 통신하기 위해 두 노드, 서버 및 클라이언트 간의 연결을 설정하는 작업이 포함됩니다. 서버는 통신 채널에서 수신기 역할을 하며 IP 주소의 특정 포트에서 클라이언트의 말을 듣습니다. 반면에 클라이언트는 통신 채널에서 커뮤니케이터 역할을 합니다. 클라이언트는 연결을 생성하고 서버와 접촉하기 위해 서버에 접속합니다. 이 기사의 목적은 C++의 소켓 프로그래밍에 대한 포괄적이고 자세한 가이드를 제공하는 것입니다. 기본 사항을 다루고 실제 예제를 제시하며 코드에 대한 자세한 설명을 제공합니다.

클라이언트-서버 모델 구축

소켓 프로그래밍은 소켓을 사용하여 서버와 클라이언트 사이에 통신 채널을 구축하는 프로세스입니다. 다음 예제 코드에서 클라이언트는 서버와의 연결을 시작하고 서버는 클라이언트 연결을 수락하도록 설정됩니다. 네트워크 통신 내에서 핵심 작업을 보여줌으로써 서버 및 클라이언트 코드 세그먼트를 이해해 보겠습니다. 다음은 서버 측 코드입니다. 먼저 코드를 본 다음, 코드를 하나씩 자세히 설명하겠습니다.

1. 서버측







모델의 서버측 코드는 다음과 같습니다. 코드에서 무슨 일이 일어나고 있는지 살펴보겠습니다.



#include
#include
#include
#include

사용하여 네임스페이스 성병 ;

#포트 8080 정의
#define MAX_BUF_SIZE 1024

정수 기본 ( ) {
정수 ser_socket, cli_socket ;
구조체 sockaddr_in ser_address, cli_address ;
버프 [ MAX_BUF_SIZE ] = { 0 } ;

만약에 ( ( ser_socket = 소켓 ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
테러 ( '소켓 생성 오류' ) ;
출구 ( 종료_실패 ) ;
}

ser_address. 죄_가족 = OF_INET ;
ser_address. 죄_주소 . s_addr = INADDR_ANY ;
ser_address. 죄_포트 = htons ( 포트 ) ;

만약에 ( 묶다 ( be_socket, ( 구조체 양말 주소 * ) & ser_address, 크기 ( ser_address ) ) == - 1 ) {
테러 ( '바인드 실패' ) ;
출구 ( 종료_실패 ) ;
}

만약에 ( 듣다 ( be_socket, ) == - 1 ) {
테러 ( '듣지 못했습니다.' ) ;
출구 ( 종료_실패 ) ;
}

시합 << '포트에서 수신 대기하는 서버' << 포트 << '... \N ' ;

socklen_t cli_address_len = 크기 ( cli_address ) ;
만약에 ( ( cli_socket = 수용하다 ( be_socket, ( 구조체 양말 주소 * ) & cli_주소, & cli_address_len ) ) == - 1 ) {
테러 ( '수락 실패' ) ;
출구 ( 종료_실패 ) ;
}

읽다 ( cli_socket, buf, MAX_BUF_SIZE ) ;
시합 << '클라이언트의 메시지는 다음과 같습니다. ' << 버프 << ;

보내다 ( cli_소켓, '서버의 메시지' , strlen ( '서버의 메시지' ) , 0 ) ;

닫다 ( cli_socket ) ;
닫다 ( ser_socket ) ;

반품 0 ;
}

주어진 예제는 C++ 프로그램의 서버측 코드입니다. 이 코드는 단일 특정 포트에서 연결을 수신하는 간단한 TCP 서버에서 작동합니다. 연결이 성공적으로 생성되면 서버는 클라이언트에서 보낸 메시지를 받게 됩니다. 그런 다음 이를 콘솔에 인쇄하고 클라이언트에 응답 메시지를 보냅니다. 각 코드 줄을 이해해 보겠습니다.



프로그램은 표준 입/출력 정의를 위한 'iostream', 문자열 처리 기능을 위한 'cstring', POSIX 운영 체제 API에 대한 액세스를 제공하는 'unistd.h' 및 'arpa/inet.h' 라이브러리를 포함하는 것으로 시작됩니다. 인터넷 작업을 수행합니다. '#define PORT 8080' 문은 서버가 수신할 포트 번호 8080을 정의한다는 의미입니다. '#define MAX_BUF_SIZE 1024'는 들어오는 데이터의 최대 버퍼 크기인 1024를 의미합니다.





메인 함수에서는 각각 서버와 클라이언트를 모두 나타내기 위해 “ser_socket”과 “cli_socket”이라는 두 개의 변수가 초기화됩니다. 'struct' 유형의 'sockaddr_in', 'ser_address' 및 'cli_address'인 다른 세 가지 변수는 서버 및 클라이언트에 대한 주소 구조로 초기화됩니다. 그 후, 클라이언트로부터 오는 데이터를 저장하는 'buf'라는 버퍼가 초기화됩니다.

'if' 조건의 소켓() 함수는 새로운 TCP 소켓을 생성합니다. AF_INET은 IPv4를 나타내고, SOCK_STREAM은 연결 지향적이고 신뢰할 수 있는 TCP 소켓을 나타내며, 마지막 인수인 0은 기본 TCP 프로토콜을 선택하기 위해 제공되고, INADDR_ANY는 모든 IP 주소의 연결을 허용하며, htons(PORT)는 포트 번호를 호스트 바이트 순서를 네트워크 바이트 순서로 바꿉니다.



모든 것이 올바르게 정의되었으므로 다음 단계는 서버를 지정된 포트의 목록으로 설정하고 모든 네트워크 인터페이스에서 연결을 수락하는 것입니다. 소켓은 바인딩() 메소드에 의해 'ser_address'의 정보와 함께 제공됩니다. 바인딩이 실패하면 오류를 인쇄하고 프로세스를 종료합니다. accept() 함수는 클라이언트와의 연결을 위해 새 소켓을 여는 반면, Listen() 함수는 서버에 들어오는 연결을 기다리도록 지시합니다. accept() 함수가 실패하면 오류 메시지가 인쇄되고 함수가 종료됩니다.

다음으로, 서버는 read() 함수를 사용하여 클라이언트 메시지를 'buf' 버퍼로 읽은 다음 이를 콘솔에 인쇄합니다. send() 함수는 서버가 클라이언트에 응답하여 메시지를 보내는 데 사용됩니다. 마지막으로 close()를 사용하여 서버는 클라이언트의 소켓을 닫고 프로그램을 종료하여 모든 연결이 올바르게 닫히고 데이터 침해 가능성이 없도록 합니다.

2. 클라이언트 측

이제 클라이언트 모델에서 어떤 일이 일어나는지 살펴보겠습니다.

#include
#include
#include
#include

#포트 8080 정의
#define SERVER_IP '127.0.0.1'

정수 기본 ( ) {
정수 cli_socket ;
구조체 sockaddr_in ser_address ;
const * 메시지 = '클라이언트가 인사말을 보내고 있습니다!' ;

만약에 ( ( cli_socket = 소켓 ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
테러 ( '소켓 생성 오류' ) ;
출구 ( 종료_실패 ) ;
}

ser_address. 죄_가족 = OF_INET ;
ser_address. 죄_포트 = htons ( 포트 ) ;

만약에 ( inet_pton ( AF_INET, SERVER_IP, & ser_address. 죄_주소 ) <= 0 ) {
테러 ( '잘못된 주소' ) ;
출구 ( 종료_실패 ) ;
}

만약에 ( 연결하다 ( cli_소켓, ( 구조체 양말 주소 * ) & ser_address, 크기 ( ser_address ) ) == - 1 ) {
테러 ( '연결 실패' ) ;
출구 ( 종료_실패 ) ;
}
보내다 ( cli_socket, 메시지, strlen ( 메시지 ) , 0 ) ;

버프 [ 1024 ] = { 0 } ;
읽다 ( cli_socket, 버프, 크기 ( 버프 ) ) ;
성병 :: 시합 << '서버 응답: ' << 버프 << 성병 :: ;

닫다 ( cli_socket ) ;
반품 0 ;
}

프로그램이 어떻게 작동하는지 이해하기 위해 각 코드 줄을 살펴보겠습니다.

동일한 4개의 라이브러리(iostream, cstring, unistd.h 및 arpa/inet.h)가 클라이언트 측에도 포함되어 있습니다. 포트 번호도 로컬 호스트 127.0.0.1의 IP 주소와 함께 정의됩니다. 서버에 전달해야 할 메시지가 제공됩니다. 클라이언트와 서버는 다음 단계에 따라 연결을 설정해야 합니다.

'if ((client_socket = 소켓(AF_INET, SOCK_STREAM, 0)) == -1);' 스트림 유형과 기본 프로토콜인 TCP를 사용하여 IPv4용 소켓을 생성합니다. perror()는 소켓() 함수가 연결 설정에 실패하고 프로그램을 종료하는 경우 오류 세부 정보를 인쇄합니다.

'server_address.sin_port = htons(PORT);' 네트워크 바이트 순서로 변환한 후 포트 번호를 설정합니다. 그 후, 주소에 문제가 있는 경우 인쇄되는 '잘못된 주소'라는 또 다른 실패 메시지가 여기에 표시됩니다. 'ser_address'에서 주소를 찾으면 클라이언트가 서버에 연결됩니다. 연결에 실패하면 오류 세부 정보가 인쇄됩니다. send() 함수는 메시지를 서버로 전송하여 메시지에 플래그가 포함되어 있지 않은지 확인합니다.

서버로부터 응답을 수신하고 저장하기 위해 'char' 유형의 'buf'라는 버퍼가 초기화됩니다. read() 함수는 서버의 응답을 버퍼로 읽어 들입니다. 마지막으로 서버의 응답이 콘솔에 인쇄됩니다. 마지막으로 소켓을 종료하기 위해 close() 문을 사용하여 연결을 닫습니다. 다음은 프로그램의 출력입니다.

결론

소켓 프로그래밍은 컴퓨터 과학에서 네트워크 통신의 중요한 부분입니다. 이를 통해 네트워크를 통해 통신할 수 있는 애플리케이션을 개발할 수 있으며 단순한 클라이언트-서버 아키텍처부터 구조화된 분산 시스템까지 광범위한 가능성을 실현할 수 있습니다. 프로그래밍 컨텍스트에서 소켓이 생성되면 프로그램은 프로토콜, TCP 또는 UDP와 같은 엔드포인트 특성과 IP 주소 및 포트 번호와 같은 네트워크 주소를 구성해야 합니다. 이 소켓을 통해 서버는 데이터를 보내고 받을 수 있습니다. 이 기사에서는 소켓 프로그래밍에서 클라이언트-서버 모델이 작동하는 방식에 대한 실제 예를 보여줍니다.