2025.02.01 - [네트워크 프로그래밍] - TCP 소켓 프로그래밍 기초: 서버와 클라이언트 구현하기
TCP 소켓 프로그래밍 기초: 서버와 클라이언트 구현하기
네트워크 프로그래밍에서 가장 기본적인 개념 중 하나는 TCP 소켓 프로그래밍입니다. TCP는 신뢰성 있는 데이터 전송을 보장하는 연결 지향 프로토콜로, 서버와 클라이언트 간의 안정적인 통신을
roblogs.tistory.com
TCP 소켓 프로그래밍에 이어 이번 글에서는 UDP(User Datagram Protocol) 소켓 프로그래밍에 대해 다룹니다. UDP는 TCP와 달리 연결을 설정하지 않고 데이터를 빠르게 전송하는 특징이 있습니다. 이를 통해 실시간 데이터 전송이나 경량 네트워크 애플리케이션에 적합한 프로토콜입니다. 본 글에서는 UDP 소켓의 개념을 설명하고, C 언어를 이용해 간단한 서버와 클라이언트를 구현하는 방법을 소개합니다.
1. UDP 소켓이란?
UDP는 비연결형(Connectionless) 프로토콜로, 송신자가 데이터를 전송할 때 연결을 설정하지 않습니다. 그 결과 데이터 전송 속도가 빠르고, 오버헤드가 적지만, 패킷 손실이 발생할 수 있습니다.
UDP의 특징
- 비연결형 프로토콜: TCP와 달리 송신자와 수신자가 연결을 설정할 필요 없음
- 빠른 데이터 전송: 연결 설정 과정이 없으므로 응답 속도가 빠름
- 신뢰성 부족: 패킷이 손실될 가능성이 있음 (수신 확인이 필요하면 별도의 로직 구현 필요)
- 데이터 순서 보장 없음: 네트워크 환경에 따라 패킷이 순서대로 도착하지 않을 수 있음
2. UDP 서버와 클라이언트의 동작 방식
UDP에서는 서버와 클라이언트가 독립적으로 동작하며, 연결 과정이 없습니다.
UDP 서버 동작 과정
- 소켓 생성: 데이터를 수신할 소켓을 생성
- 주소 바인딩: 특정 IP와 포트에 소켓을 연결
- 데이터 수신 대기: 클라이언트로부터 데이터를 기다림
- 데이터 수신 후 처리: 수신한 데이터를 처리하고 응답을 전송
UDP 클라이언트 동작 과정
- 소켓 생성: 데이터를 전송할 소켓을 생성
- 서버로 데이터 전송: 서버의 IP와 포트로 데이터를 보냄
- 응답 수신 대기: 서버가 응답을 보내면 이를 수신
- 응답 처리 후 종료: 데이터를 처리한 후 소켓 종료
3. UDP 서버 구현
UDP 서버는 클라이언트의 요청을 기다렸다가 메시지를 수신하고 응답을 보내는 역할을 합니다.
3.1 코드 분석
아래 서버 코드에서 사용된 주요 API와 기능을 설명합니다.
- socket(): UDP 소켓을 생성합니다.
- bind(): 소켓을 특정 IP와 포트에 바인딩합니다.
- recvfrom(): 클라이언트로부터 데이터를 수신합니다.
- sendto(): 클라이언트에게 데이터를 전송합니다.
- close(): 소켓을 닫고 종료합니다.
3.2 UDP 서버 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
// 1. UDP 소켓 생성
server_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_fd == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 서버 주소 설정 및 바인딩
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("UDP Server listening on port %d\n", PORT);
// 3. 데이터 수신 및 응답 전송
recvfrom(server_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client_addr, &client_len);
printf("Received: %s\n", buffer);
sendto(server_fd, "Hello, Client!", 14, 0, (struct sockaddr *)&client_addr, client_len);
// 4. 소켓 종료
close(server_fd);
return 0;
}
4. UDP 클라이언트 구현
UDP 클라이언트는 서버에 데이터를 전송하고 응답을 받습니다.
4.1 코드 분석
- socket(): UDP 소켓을 생성합니다.
- sendto(): 서버에 데이터를 전송합니다.
- recvfrom(): 서버의 응답을 수신합니다.
- close(): 소켓을 닫고 종료합니다.
4.2 UDP 클라이언트 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock;
struct sockaddr_in server_addr;
socklen_t addr_len = sizeof(server_addr);
char buffer[BUFFER_SIZE] = "Hello, Server!";
// 1. UDP 소켓 생성
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 서버 주소 설정
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
// 3. 데이터 전송 및 응답 수신
sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr *)&server_addr, addr_len);
recvfrom(sock, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len);
printf("Received: %s\n", buffer);
// 4. 소켓 종료
close(sock);
return 0;
}
5. 실행 결과
UDP 서버와 클라이언트를 실행하면 다음과 같은 결과를 확인할 수 있습니다.
- 서버 측 출력:
UDP Server listening on port 8080
Received: Hello, Server!
- 클라이언트 측 출력:
Received: Hello, Client!
6. 마무리
이번 글에서는 UDP 소켓 프로그래밍의 개념과 C 언어를 이용한 UDP 서버 및 클라이언트 구현 방법을 다루었습니다. UDP는 빠른 데이터 전송이 가능하지만 신뢰성이 부족하므로, 보완이 필요한 경우 추가적인 확인 메커니즘을 고려해야 합니다.
'리눅스 시스템 및 네트워크 프로그래밍 > 네트워크 프로그래밍' 카테고리의 다른 글
논블로킹 소켓과 멀티플렉싱: select, poll, epoll 비교 (0) | 2025.02.02 |
---|---|
TCP 소켓 프로그래밍 기초: 서버와 클라이언트 구현하기 (0) | 2025.02.01 |
댓글