소켓에 대해 공부를 하게되면 항상 TCP만 사용하다 보니,
UDP를 한번씩 깜빠깜빡해 생각난 김에 정리해 보자.
P로 끝난걸로 프로토콜임을 짐작할 수 있다.
전송 계층 프로토콜 중 하나로, IP 스택의 일부로 사용되며, 데이터를 빠르게 보내고 받는 데 사용.
- 비연결 지향 (Connectionless):
UDP는 연결 설정 과정을 거치지 않고 데이터를 전송하여, 이는 TCP와 대조적으로 연결 지향적인 프로토콜이 아님을 알 수 있다. 따라서 연결 설정 및 해제와 관련된 오버헤드가 없으며, 데이터 패킷을 빠르게 보내고 받을 수 있다.
- 데이터그램(데이터 패킷):
UDP에서 데이터는 데이터그램으로 나뉘어 전송됩니다. 각 데이터그램은 독립적으로 처리되며, 순서가 보장되지 않아, 이러한 특성으로 인해 데이터가 일부 손실될 수 있으며, 순서가 바뀔 수 있다.
- 신뢰성 부족:
UDP는 오류 검출 기능은 제공하지만, 오류 복구를 지원하지 않는다. 따라서 데이터 전송의 신뢰성이 보장되지 않음. 이런 특성은 실시간 응용 프로그램에 유용할 수 있다.
- 소스 포트 및 대상 포트:
UDP 패킷은 송신자와 수신자를 식별하기 위한 포트 번호를 사용하며, 각 UDP 패킷에는 송신자 포트와 수신자 포트가 포함되어 있다. 이를 사용하여 데이터를 올바른 프로세스로 라우팅 할 수 있다.
- 빠른 전송:
연결 설정 및 유지에 소요되는 오버헤드가 없기 때문에, 실시간 응용 프로그램에서 사용되며, 지연 시간이 중요한 상황에서 유용.
C++을 사용하여 단순한 UDP 클라이언트와 서버를 만들어보자.
클라 : [메시지] -> 서버
서버 : [메시지] 출력.
#include <iostream>
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize winsock" << std::endl;
return 1;
}
// 소켓 생성
SOCKET serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Failed to create socket" << std::endl;
WSACleanup();
return 1;
}
// 서버 주소 설정
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345); // 포트 번호
serverAddr.sin_addr.s_addr = INADDR_ANY;
// 소켓 바인딩
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Failed to bind socket" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "UDP server is running..." << std::endl;
while (true) {
char buffer[1024];
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
// 메시지 수신
int bytesReceived = recvfrom(serverSocket, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientAddr, &clientAddrSize);
if (bytesReceived == SOCKET_ERROR) {
std::cerr << "Error in recvfrom" << std::endl;
continue;
}
buffer[bytesReceived] = '\0';
std::cout << "Received message from " << inet_ntoa(clientAddr.sin_addr) << ": " << buffer << std::endl;
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
UDP 클라이언트 코드:
#include <iostream>
#include <Winsock2.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
int main() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "Failed to initialize winsock" << std::endl;
return 1;
}
// 소켓 생성
SOCKET clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Failed to create socket" << std::endl;
WSACleanup();
return 1;
}
// 서버 주소 설정
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345); // 서버 포트 번호
serverAddr.sin_addr.s_addr = inet_addr("서버의_IP_주소"); // 서버의 IP 주소로 변경
while (true) {
std::string message;
std::cout << "Enter a message (or 'exit' to quit): ";
std::getline(std::cin, message);
if (message == "exit") {
break;
}
// 메시지 전송
sendto(clientSocket, message.c_str(), message.length(), 0, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
}
closesocket(clientSocket);
WSACleanup();
return 0;
}
UDP 통신은 연결 지향이 아니므로 오류 처리와 예외 상황을 고려해야 한다ㅣ.