c++

C++ 네트워크 프로그래밍과 소켓 통신

난개발자 2025. 2. 4. 23:13
728x90

1. 네트워크 프로그래밍이란?

네트워크 프로그래밍은 컴퓨터 간의 데이터 전송을 위해 프로그래밍하는 기술입니다. 이를 통해 클라이언트와 서버 간의 통신을 구현할 수 있습니다.

(1) 소켓(Socket)이란?

  • 소켓은 네트워크를 통해 데이터를 송수신하기 위한 양 끝단의 인터페이스입니다.
  • C++에서는 주로 BSD 소켓 API를 사용하여 네트워크 통신을 구현합니다.

(2) 클라이언트-서버 모델

  1. 서버(Server): 클라이언트의 요청을 기다리고 응답하는 역할
  2. 클라이언트(Client): 서버에 요청을 보내고 응답을 받는 역할

2. C++에서 소켓 프로그래밍 준비하기

C++에서 소켓 프로그래밍을 위해 다음 헤더 파일을 포함해야 합니다.

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
  • <sys/socket.h>: 소켓 관련 함수 정의
  • <arpa/inet.h>: IP 주소 변환 함수
  • <unistd.h>: 시스템 호출 함수 (close() 등)

3. TCP 소켓 프로그래밍: 서버 구현

(1) TCP 서버 기본 코드

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    const char* message = "Hello from server!";

    // 소켓 생성
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == 0) {
        perror("소켓 생성 실패");
        exit(EXIT_FAILURE);
    }

    // 소켓 옵션 설정
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));

    // 주소 및 포트 설정
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);

    // 소켓에 주소 바인딩
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("바인딩 실패");
        exit(EXIT_FAILURE);
    }

    // 연결 대기 상태로 전환
    if (listen(server_fd, 3) < 0) {
        perror("리스닝 실패");
        exit(EXIT_FAILURE);
    }

    cout << "서버가 클라이언트 요청을 기다리고 있습니다..." << endl;

    // 클라이언트 연결 수락
    new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
    if (new_socket < 0) {
        perror("연결 수락 실패");
        exit(EXIT_FAILURE);
    }

    // 클라이언트로부터 메시지 수신
    read(new_socket, buffer, 1024);
    cout << "클라이언트로부터 받은 메시지: " << buffer << endl;

    // 클라이언트로 메시지 전송
    send(new_socket, message, strlen(message), 0);
    cout << "메시지를 클라이언트로 전송했습니다." << endl;

    // 소켓 종료
    close(new_socket);
    close(server_fd);

    return 0;
}

(2) 코드 설명

  • socket(): 소켓 생성
  • bind(): 소켓에 IP 주소와 포트 번호 연결
  • listen(): 클라이언트 연결 대기
  • accept(): 클라이언트 연결 수락
  • read(): 클라이언트로부터 데이터 수신
  • send(): 클라이언트로 데이터 전송

(3) 서버 실행

g++ server.cpp -o server
./server

4. TCP 소켓 프로그래밍: 클라이언트 구현

(1) TCP 클라이언트 기본 코드

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[1024] = {0};

    // 소켓 생성
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("소켓 생성 실패");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);

    // IP 주소 변환
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("주소 변환 실패");
        return -1;
    }

    // 서버에 연결 요청
    if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("연결 실패");
        return -1;
    }

    // 서버로 메시지 전송
    const char* message = "Hello from client!";
    send(sock, message, strlen(message), 0);
    cout << "메시지를 서버로 전송했습니다." << endl;

    // 서버로부터 응답 수신
    read(sock, buffer, 1024);
    cout << "서버로부터 받은 메시지: " << buffer << endl;

    // 소켓 종료
    close(sock);

    return 0;
}

(2) 클라이언트 실행

g++ client.cpp -o client
./client

5. 서버-클라이언트 통신 결과

  1. 서버 실행 결과:
서버가 클라이언트 요청을 기다리고 있습니다...
클라이언트로부터 받은 메시지: Hello from client!
메시지를 클라이언트로 전송했습니다.
  1. 클라이언트 실행 결과:
메시지를 서버로 전송했습니다.
서버로부터 받은 메시지: Hello from server!

6. 멀티 클라이언트 지원 서버 구현

여러 클라이언트의 요청을 처리하기 위해 멀티스레딩 서버를 구현할 수 있습니다.

#include <iostream>
#include <thread>
#include <vector>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;

void handleClient(int client_socket) {
    char buffer[1024] = {0};
    read(client_socket, buffer, 1024);
    cout << "클라이언트로부터 받은 메시지: " << buffer << endl;

    const char* message = "서버 응답: 요청을 처리했습니다.";
    send(client_socket, message, strlen(message), 0);

    close(client_socket);
}

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);

    bind(server_fd, (struct sockaddr*)&address, sizeof(address));
    listen(server_fd, 5);

    cout << "서버가 여러 클라이언트 요청을 기다리고 있습니다..." << endl;

    while (true) {
        new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
        thread t(handleClient, new_socket);
        t.detach();  // 독립적인 스레드로 실행
    }

    close(server_fd);
    return 0;
}

 

728x90