이석복 님의 KOCW 강의 "컴퓨터 네트워크"를 정리한 글입니다.
* James F. Kurose님과 Keith W. Ross 님의
"컴퓨터 네트워킹 하향식 접근" 책을 교제로 한 강의입니다. (책의 내용은 포함되지 않았습니다)
1. 네트워크 애플리케이션의 원리
Client-Server Architecture
구분 | 서버 (Server) | 클라이언트 (Client) |
상태 | 항상 대기 상태 (대기 서버) | 요청 시에만 활성화됨 |
IP 주소 | 영구적인 고정 IP 주소를 가짐 | 동적 IP 주소를 가질 수 있음 |
데이터 센터 | 보통 데이터 센터나 서버실에 존재 | 개인 컴퓨터, 스마트폰 등 다양한 장치에서 존재 |
역할 | 서비스를 제공하고 요청을 처리 | 서버에 요청을 보내고 서버의 응답을 처리 |
예시 | 웹 서버, 데이터베이스 서버, 파일 서버 등 | 웹 브라우저, 이메일 클라이언트, 모바일 앱 등 |
Process Communicating
- 프로세스 간 통신을 의미
socket
- 네트워크에서 프로세스 간 통신을 위한 엔드포인트 (통신 인터페이스)
- 소켓을 통해 메시지를 주고받음
- identifier: ip + port
2. 웹과 HTTP
HTTP
항목 | 설명 |
프로토콜 | HTTP (HyperText Transfer Protocol) |
모델 | Client-Server 모델 |
계층 | Application Layer (응용 계층) |
기반 | TCP 기반 |
상태 |
Stateless (과거 클라이언트 요청에 대한 정보를 유지하지 않음)
|
TCP 연결 재사용 |
1. Non-persistent: 요청이 끝날 때마다 TCP 연결을 끊음.
2. Persistent: 한 문서에 여러 리소스 요청이 있을 때 TCP 연결을 재사용 |
rtt
- 요청-응답 간의 소요 시간
response time
- 요청-응답까지 걸리는 총 시간
- Non-persistent
- rtt * 2 + file transmission time
- 연결을 끊고 새로운 연결을 설정하므로
- persistent
- rtt + file transmission time
3. 인터넷 전자메일
4. DNS: 인터넷의 디렉터리 서비스
5. P2P 파일 분배
6. 비디오 스트리밍과 콘텐츠 분배 네트워크
7. 소켓 프로그래밍: 네트워크 애플리케이션 생성
- 전송 계층 프로토콜 별 소켓 타입이 달라짐
SOCK_STREAM (TCP)
- 연결 지향적인 방식으로 데이터 전송의 신뢰성을 보장합니다
- 순서대로 전송되며 손실된 데이터는 재전송됩니다.
절차
단계 | 서버 | 클라이언트 | 설명 |
1. 소켓 열기 | socket() | socket() |
서버와 클라이언트가 각각 소켓을 생성합니다.
|
2. IP 주소 바인딩 | bind() | - |
서버는 자신이 사용할 IP 주소와 포트를 바인딩합니다.
|
3. 서버 모드로 전환 | listen() | - |
서버는 클라이언트의 연결을 기다리는 상태로 대기합니다.
|
4. 연결 수락 | accept() | - |
클라이언트로부터 연결이 오면 서버는 연결을 수락하고, 새로운 소켓을 반환합니다.
(블로킹 상태) |
5. 클라이언트 연결 | - | connect() |
클라이언트는 서버에 연결을 시도합니다.
이때 3-way handshake가 발생합니다. |
6. 요청 전송 | - | write() |
클라이언트는 서버로 데이터를 전송합니다.
|
7. 서버 응답 | read() | - |
서버는 클라이언트의 요청에 응답합니다.
|
8. 응답 받기 | - | read() |
클라이언트는 서버의 응답을 받습니다.
|
예시
더보기
서버 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 12345
#define MAX_BUFFER_SIZE 1024
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len;
char buffer[MAX_BUFFER_SIZE];
// 서버 소켓 생성
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("소켓 생성 실패");
exit(1);
}
// 서버 주소 설정
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // 모든 IP에서 접속 가능
server_addr.sin_port = htons(PORT);
// 소켓에 주소 바인딩
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("바인딩 실패");
exit(1);
}
// 연결 대기 상태로 설정
if (listen(server_socket, 5) < 0) {
perror("리스닝 실패");
exit(1);
}
printf("서버 대기 중...\n");
// 클라이언트 연결 수락
client_len = sizeof(client_addr);
if ((client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_len)) < 0) {
perror("클라이언트 연결 수락 실패");
exit(1);
}
printf("클라이언트 연결됨: %s\n", inet_ntoa(client_addr.sin_addr));
// 클라이언트로부터 데이터 받기
ssize_t n = recv(client_socket, buffer, MAX_BUFFER_SIZE, 0);
if (n < 0) {
perror("데이터 수신 실패");
exit(1);
}
buffer[n] = '\0'; // null-terminate
printf("클라이언트로부터 받은 데이터: %s\n", buffer);
// 클라이언트에게 응답 보내기
send(client_socket, "서버가 응답을 보냅니다.", 24, 0);
// 소켓 닫기
close(client_socket);
close(server_socket);
return 0;
}
더보기
클라이언트 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 12345
#define MAX_BUFFER_SIZE 1024
int main() {
int client_socket;
struct sockaddr_in server_addr;
char buffer[MAX_BUFFER_SIZE];
// 클라이언트 소켓 생성
if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("소켓 생성 실패");
exit(1);
}
// 서버 주소 설정
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 서버 IP (로컬호스트)
// 서버에 연결
if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("서버 연결 실패");
exit(1);
}
printf("서버에 연결됨\n");
// 서버로 데이터 전송
const char *message = "안녕하세요, 서버!";
send(client_socket, message, strlen(message), 0);
printf("서버로 데이터 전송: %s\n", message);
// 서버로부터 응답 받기
ssize_t n = recv(client_socket, buffer, MAX_BUFFER_SIZE, 0);
if (n < 0) {
perror("서버로부터 응답 수신 실패");
exit(1);
}
buffer[n] = '\0'; // null-terminate
printf("서버로부터 받은 응답: %s\n", buffer);
// 소켓 닫기
close(client_socket);
return 0;
}
출처
'Network' 카테고리의 다른 글
[컴퓨터 네트워킹 하향식 접근] 3-3. 트랜스포트 계층: UDP (1) | 2025.03.28 |
---|---|
[컴퓨터 네트워킹 하향식 접근] 3-2. 트랜스포트 계층: TCP (1) | 2025.03.28 |
[러닝 HTTP/2] 1. HTTP의 진화 (0) | 2025.03.28 |
[컴퓨터 네트워킹 하향식 접근] 3-1. 트랜스포트 계층: 개요 (0) | 2025.03.27 |
[컴퓨터 네트워킹 하향식 접근] 1. 컴퓨터와 네트워크 인터넷 (0) | 2025.03.27 |