소켓 프로그래밍의 기초

소켓 프로그래밍은 컴퓨터 네트워크 상에서 두 장치(클라이언트와 서버)가 데이터를 주고받을 수 있도록 통신을 설정하고 관리하는 기술입니다. 이를 위해 다음과 같은 작업 흐름이 필요합니다:

클라이언트-서버 모델의 요약

  1. 서버(Server):

    • 소켓을 생성하고 네트워크 상의 특정 주소(IP)와 포트에 바인딩.
    • 클라이언트의 요청을 기다리며, 요청이 올 때 이를 수락하여 통신 소켓을 생성.
    • 데이터를 주고받으며 클라이언트의 요청 처리.
  2. 클라이언트(Client):

    • 서버의 주소(IP)와 포트를 사용하여 연결 요청.
    • 데이터를 전송하거나 서버로부터 데이터를 수신.

소켓 프로그래밍 코드의 세부 분석

서버 코드

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
  1. #include <iostream>:

    • C++ 표준 입출력 스트림을 사용하기 위해 포함.
    • std::cout, std::cin 등을 사용 가능하게 함.
  2. #include <cstring>:

    • C 스타일의 문자열 처리 함수 사용을 위해 포함.
    • 예: memset, strcpy.
  3. #include <sys/socket.h>:

    • 소켓 생성 및 통신 관련 함수 제공.
    • 예: socket, bind, listen, accept, send, recv.
  4. #include <netinet/in.h>:

    • 네트워크 주소 구조체 및 데이터 형식을 정의.
    • 예: sockaddr_in, htons, htonl.
  5. #include <unistd.h>:

    • POSIX 운영체제에서 파일 디스크립터 관련 기능 제공.
    • 예: close.

#define PORT 8080
  1. #define PORT 8080:
    • 서버가 사용할 포트를 정의.
    • 클라이언트가 이 포트를 통해 서버에 연결.

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

    • server_fd: 서버 소켓 파일 디스크립터.
    • new_socket: 클라이언트와 통신에 사용할 새 소켓 디스크립터.
  2. struct sockaddr_in address;:

    • IPv4 주소 정보를 저장하는 구조체.
    • 서버의 IP와 포트 정보가 설정됨.
  3. int opt = 1;:

    • 소켓 옵션 설정 값. 재사용 여부에 사용.
  4. int addrlen = sizeof(address);:

    • address 구조체의 크기 저장.
    • accept 함수 호출 시 사용.
  5. char buffer[1024] = {0};:

    • 클라이언트로부터 데이터를 수신할 버퍼.
  6. const char *hello = "Hello from server";:

    • 클라이언트에게 전송할 메시지.

server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}
  1. socket(AF_INET, SOCK_STREAM, 0):

    • 소켓 생성.
      • AF_INET: IPv4 프로토콜.
      • SOCK_STREAM: TCP 프로토콜.
      • 0: 자동으로 적합한 프로토콜 선택.
  2. if (server_fd == 0):

    • 소켓 생성 실패 여부 확인.
    • 실패 시 에러 메시지를 출력하고 프로그램 종료.

if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
    perror("setsockopt");
    exit(EXIT_FAILURE);
}
  1. setsockopt():

    • 소켓 옵션을 설정.
      • SOL_SOCKET: 소켓 레벨 옵션.
      • SO_REUSEADDR: 주소 재사용 가능.
      • SO_REUSEPORT: 포트 재사용 가능.
  2. 에러 체크:

    • 설정 실패 시 에러 메시지를 출력하고 종료.

address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
  1. address.sin_family = AF_INET:

    • IPv4 주소 체계 설정.
  2. address.sin_addr.s_addr = INADDR_ANY:

    • 모든 네트워크 인터페이스의 요청을 수신.
  3. address.sin_port = htons(PORT):

    • htons: 포트를 빅엔디안으로 변환.
    • 네트워크 통신에서 데이터는 빅엔디안 형식으로 전송됨.

if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}
  1. bind():

    • 소켓을 IP와 포트에 바인딩.
    • 서버가 요청을 수신할 주소 설정.
  2. 에러 체크:

    • 바인딩 실패 시 에러 메시지를 출력하고 종료.

if (listen(server_fd, 3) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
}
  1. listen():
    • 소켓을 연결 대기 상태로 전환.
    • 3: 최대 대기 연결 수.

new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen);
if (new_socket < 0) {
    perror("accept");
    exit(EXIT_FAILURE);
}
  1. accept():

    • 클라이언트의 연결 요청 수락.
    • 새로운 소켓 디스크립터 반환.
  2. 에러 체크:

    • 실패 시 에러 메시지를 출력하고 종료.

read(new_socket, buffer, 1024);
printf("Message from client: %s\n", buffer);
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
  1. read():

    • 클라이언트로부터 데이터를 수신.
    • buffer에 저장.
  2. printf:

    • 수신한 데이터를 출력.
  3. send():

    • 클라이언트에게 데이터를 전송.
    • 문자열 길이만큼 전송.

close(new_socket);
close(server_fd);
return 0;
  1. close():

    • 소켓 리소스 해제.
    • new_socketserver_fd 모두 닫아야 함.
  2. return 0:

    • 프로그램 정상 종료.

클라이언트 코드 분석

전체 흐름

  1. 소켓 생성: 서버와의 통신 준비.
  2. 서버 연결: 서버의 IP와 포트를 통해 연결 요청.
  3. 데이터 송수신: 메시지 전송 및 수신.
  4. 소켓 종료: 리소스 정리.

구체적 설명

  • 클라이언트 코드도 서버 코드와 유사하나, 연결 요청과 데이터 송수신만 수행.
profile
李家네_공부방

0개의 댓글