C++ 네트워크 | "소켓 프로그래밍" 기초 [TCP/UDP]
이 글의 핵심
C++ 네트워크에 대해 정리한 개발 블로그 글입니다. #include <iostream> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <cstring> using…
TCP 서버
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
using namespace std;
int main() {
// 1. 소켓 생성
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
cerr << "소켓 생성 실패" << endl;
return 1;
}
// 2. 주소 설정
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
// 3. 바인드
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
cerr << "바인드 실패" << endl;
return 1;
}
// 4. 리슨
if (listen(serverSocket, 5) < 0) {
cerr << "리슨 실패" << endl;
return 1;
}
cout << "서버 시작: 포트 8080" << endl;
// 5. 연결 수락
sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
int clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientLen);
if (clientSocket < 0) {
cerr << "연결 수락 실패" << endl;
return 1;
}
cout << "클라이언트 연결됨" << endl;
// 6. 데이터 수신
char buffer[1024] = {0};
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
cout << "받은 메시지: " << buffer << endl;
// 7. 데이터 전송
const char* response = "Hello from server!";
send(clientSocket, response, strlen(response), 0);
// 8. 소켓 닫기
close(clientSocket);
close(serverSocket);
return 0;
}
TCP 클라이언트
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
using namespace std;
int main() {
// 1. 소켓 생성
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket < 0) {
cerr << "소켓 생성 실패" << endl;
return 1;
}
// 2. 서버 주소 설정
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr) <= 0) {
cerr << "주소 변환 실패" << endl;
return 1;
}
// 3. 연결
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
cerr << "연결 실패" << endl;
return 1;
}
cout << "서버에 연결됨" << endl;
// 4. 데이터 전송
const char* message = "Hello from client!";
send(clientSocket, message, strlen(message), 0);
// 5. 응답 수신
char buffer[1024] = {0};
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
cout << "서버 응답: " << buffer << endl;
// 6. 소켓 닫기
close(clientSocket);
return 0;
}
UDP 서버
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
using namespace std;
int main() {
// UDP 소켓 생성
int serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
cout << "UDP 서버 시작: 포트 8080" << endl;
char buffer[1024];
sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
// 데이터 수신
int bytesRead = recvfrom(serverSocket, buffer, sizeof(buffer), 0,
(sockaddr*)&clientAddr, &clientLen);
buffer[bytesRead] = '\0';
cout << "받은 메시지: " << buffer << endl;
// 응답 전송
const char* response = "UDP response";
sendto(serverSocket, response, strlen(response), 0,
(sockaddr*)&clientAddr, clientLen);
close(serverSocket);
return 0;
}
UDP 클라이언트
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
using namespace std;
int main() {
int clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
// 데이터 전송
const char* message = "UDP message";
sendto(clientSocket, message, strlen(message), 0,
(sockaddr*)&serverAddr, sizeof(serverAddr));
// 응답 수신
char buffer[1024];
socklen_t serverLen = sizeof(serverAddr);
int bytesRead = recvfrom(clientSocket, buffer, sizeof(buffer), 0,
(sockaddr*)&serverAddr, &serverLen);
buffer[bytesRead] = '\0';
cout << "서버 응답: " << buffer << endl;
close(clientSocket);
return 0;
}
실전 예시
예시 1: 멀티 클라이언트 서버
#include <iostream>
#include <thread>
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
using namespace std;
void handleClient(int clientSocket) {
char buffer[1024];
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead > 0) {
buffer[bytesRead] = '\0';
cout << "받은 메시지: " << buffer << endl;
send(clientSocket, buffer, bytesRead, 0); // 에코
}
close(clientSocket);
}
int main() {
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
listen(serverSocket, 10);
cout << "멀티 클라이언트 서버 시작" << endl;
vector<thread> threads;
while (true) {
sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
int clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientLen);
if (clientSocket >= 0) {
threads.emplace_back(handleClient, clientSocket);
}
}
for (auto& t : threads) {
if (t.joinable()) t.join();
}
close(serverSocket);
return 0;
}
예시 2: HTTP 간단 서버
#include <iostream>
#include <sstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
using namespace std;
string createHTTPResponse(const string& content) {
ostringstream response;
response << "HTTP/1.1 200 OK\r\n";
response << "Content-Type: text/html\r\n";
response << "Content-Length: " << content.length() << "\r\n";
response << "\r\n";
response << content;
return response.str();
}
int main() {
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
listen(serverSocket, 5);
cout << "HTTP 서버 시작: http://localhost:8080" << endl;
while (true) {
sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
int clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientLen);
char buffer[4096];
recv(clientSocket, buffer, sizeof(buffer), 0);
string html = "<html><body><h1>Hello, World!</h1></body></html>";
string response = createHTTPResponse(html);
send(clientSocket, response.c_str(), response.length(), 0);
close(clientSocket);
}
close(serverSocket);
return 0;
}
예시 3: 채팅 서버
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
using namespace std;
vector<int> clients;
mutex clientsMutex;
void broadcast(const string& message, int sender) {
lock_guard<mutex> lock(clientsMutex);
for (int client : clients) {
if (client != sender) {
send(client, message.c_str(), message.length(), 0);
}
}
}
void handleClient(int clientSocket) {
{
lock_guard<mutex> lock(clientsMutex);
clients.push_back(clientSocket);
}
char buffer[1024];
while (true) {
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead <= 0) break;
buffer[bytesRead] = '\0';
string message(buffer);
cout << "메시지: " << message << endl;
broadcast(message, clientSocket);
}
{
lock_guard<mutex> lock(clientsMutex);
clients.erase(remove(clients.begin(), clients.end(), clientSocket), clients.end());
}
close(clientSocket);
}
int main() {
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
listen(serverSocket, 10);
cout << "채팅 서버 시작" << endl;
vector<thread> threads;
while (true) {
sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
int clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientLen);
threads.emplace_back(handleClient, clientSocket);
}
return 0;
}
자주 발생하는 문제
문제 1: Address already in use
증상: bind 실패
원인: 포트가 이미 사용 중
해결법:
int opt = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
문제 2: Broken pipe
증상: send 시 크래시
원인: 클라이언트가 연결을 끊음
해결법: recv 반환값 체크
문제 3: 블로킹
증상: accept/recv에서 멈춤
원인: 블로킹 소켓
해결법: 논블로킹 소켓 또는 select/poll 사용
FAQ
Q1: TCP vs UDP 언제 사용하나요?
A:
- TCP: 신뢰성 필요 (HTTP, 파일 전송)
- UDP: 속도 중요 (게임, 스트리밍)
Q2: 포트 번호는?
A:
- 0-1023: 시스템 예약
- 1024-49151: 등록된 포트
- 49152-65535: 동적 포트
Q3: 여러 클라이언트 처리는?
A:
- 멀티스레딩
- select/poll/epoll
- 비동기 I/O
Q4: Windows에서는?
A: Winsock API 사용 (약간 다름)
Q5: 보안은?
A: SSL/TLS 사용 (OpenSSL 라이브러리)
Q6: 네트워크 프로그래밍 학습 리소스는?
A:
- “Unix Network Programming” (Stevens)
- Beej’s Guide to Network Programming
- Boost.Asio 라이브러리
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ 소켓 프로그래밍 완벽 가이드 | TCP/UDP·소켓 옵션·논블로킹·에러 처리 [#28-1]
- C++ HTTP 클라이언트 완벽 가이드 | REST API 호출·연결 풀·타임아웃·프로덕션 패턴
- C++ Boost.Asio 입문 | io_context·async_read
관련 글
- C++ 시리즈 전체 보기
- C++ Adapter Pattern 완벽 가이드 | 인터페이스 변환과 호환성
- C++ ADL |
- C++ Aggregate Initialization |