c++
C++ 네트워크 프로그래밍과 소켓 통신
난개발자
2025. 2. 4. 23:13
728x90
1. 네트워크 프로그래밍이란?
네트워크 프로그래밍은 컴퓨터 간의 데이터 전송을 위해 프로그래밍하는 기술입니다. 이를 통해 클라이언트와 서버 간의 통신을 구현할 수 있습니다.
(1) 소켓(Socket)이란?
- 소켓은 네트워크를 통해 데이터를 송수신하기 위한 양 끝단의 인터페이스입니다.
- C++에서는 주로 BSD 소켓 API를 사용하여 네트워크 통신을 구현합니다.
(2) 클라이언트-서버 모델
- 서버(Server): 클라이언트의 요청을 기다리고 응답하는 역할
- 클라이언트(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. 서버-클라이언트 통신 결과
- 서버 실행 결과:
서버가 클라이언트 요청을 기다리고 있습니다...
클라이언트로부터 받은 메시지: Hello from client!
메시지를 클라이언트로 전송했습니다.
- 클라이언트 실행 결과:
메시지를 서버로 전송했습니다.
서버로부터 받은 메시지: 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