
반성합니다...
=========================================
에코 클라이언트/서버 로컬 통신 흐름도 (텍스트 기반)
=========================================
--- 1. 서버 준비 단계 ---
[서버 프로세스]
- 실행 시작 (./echoserveri <포트번호>)
- CALLS: Open_listenfd(포트번호)
|
|--> [커널]
| - getaddrinfo() 수행 (NULL 호스트, 포트번호, AI_PASSIVE)
| - socket() 호출 -> listenfd 생성
| - setsockopt() 호출 (SO_REUSEADDR 설정)
| - bind() 호출 (listenfd를 와일드카드 주소:포트번호에 바인딩)
| - listen() 호출 (listenfd를 리스닝 상태로 만듦)
|<-- 반환: listenfd (예: 3)
- WHILE (1) 루프 시작
- CALLS: Accept(listenfd, ...)
- 상태: **BLOCKED** (listenfd에서 클라이언트 연결 요청 대기)
--- 2. 클라이언트 연결 요청 단계 ---
[클라이언트 프로세스]
- 실행 시작 (./echoclient localhost <포트번호>)
- CALLS: Open_clientfd("localhost", 포트번호)
|
|--> [커널]
| - getaddrinfo() 수행 ("localhost", 포트번호, SOCK_STREAM)
| - socket() 호출 -> clientfd 생성 (예: 3)
| - Connect(clientfd, {127.0.0.1:포트번호}, ...) 호출
| - (루프백 통해) TCP 3-way handshake 시도
| - 클라이언트 측 임시 포트 할당 (예: 37246)
|<-- 연결 결과 대기
- 상태: **BLOCKED** (Connect 함수 내에서 연결 결과 대기)
--- 3. 연결 수립 및 준비 완료 단계 ---
[커널]
- TCP 3-way handshake 완료
- 연결 정보 생성: (127.0.0.1:37246 <-> 127.0.0.1:포트번호)
- 서버 프로세스 깨우기 (listenfd에 연결 준비 완료 이벤트)
- 클라이언트 프로세스 깨우기 (Connect 성공 이벤트)
[서버 프로세스]
- 상태: **WAKE UP** (Ready 상태) -> Running 상태
- Accept() 함수 반환
- 반환 값: 새로운 연결 소켓 connfd (예: 4)
- clientaddr 구조체에 클라이언트 주소({127.0.0.1:37246}) 채워짐
- CALLS: Getnameinfo(...) -> 클라이언트 정보 얻기
- CALLS: printf("Connected to...") -> 연결 정보 출력
- CALLS: echo(connfd) -> 에코 함수 시작
|
|--> [echo 함수 내부]
| - CALLS: Rio_readinitb(&rio, connfd)
| - CALLS: Rio_readlineb(&rio, ...) -> 데이터 기다림
| - 상태: **BLOCKED** (connfd에서 클라이언트 데이터 대기)
[클라이언트 프로세스]
- 상태: **WAKE UP** (Ready 상태) -> Running 상태
- Connect() 함수 성공 반환 (0) -> Open_clientfd() 성공 반환 (clientfd 3)
- CALLS: Rio_readinitb(&rio, clientfd)
- CALLS: printf("Connected...")
- CALLS: printf("Type input: ")
- CALLS: Fgets(..., stdin) -> 사용자 입력 기다림
- 상태: **BLOCKED** (stdin에서 사용자 입력 대기)
--- 4. 데이터 교환 단계 (클라이언트가 "Hi\\n" 전송) ---
[클라이언트 프로세스]
- 사용자가 "Hi" 입력 후 Enter
- Fgets() 함수 반환 ("Hi\n" 읽음)
- 상태: **Running**
- CALLS: Rio_writen(clientfd, "Hi\n", 3)
|
|--> [커널]
| - "Hi\n" 데이터를 루프백 통해 서버 측 connfd로 전송
| - 서버 프로세스 깨우기 (connfd에 데이터 도착 이벤트)
- CALLS: Rio_readlineb(&rio, ...) -> 서버 응답 기다림
- 상태: **BLOCKED** (clientfd에서 서버 에코 응답 대기)
[서버 프로세스 (echo 함수 내부)]
- 상태: **WAKE UP** (Ready 상태) -> Running 상태
- Rio_readlineb() 함수 반환 (3, buf="Hi\n")
- CALLS: printf("server received 3 bytes\n")
- CALLS: Rio_writen(connfd, "Hi\n", 3)
|
|--> [커널]
| - "Hi\n" 데이터를 루프백 통해 클라이언트 측 clientfd로 전송
| - 클라이언트 프로세스 깨우기 (clientfd에 데이터 도착 이벤트)
- CALLS: Rio_readlineb(&rio, ...) -> 다음 데이터 기다림
- 상태: **BLOCKED** (connfd에서 클라이언트 데이터 대기)
[클라이언트 프로세스]
- 상태: **WAKE UP** (Ready 상태) -> Running 상태
- Rio_readlineb() 함수 반환 (3, buf="Hi\n")
- CALLS: Fputs("Hi\n", stdout) -> 화면에 "Hi" 출력
- CALLS: printf("Type input: ")
- CALLS: Fgets(..., stdin) -> 사용자 입력 기다림
- 상태: **BLOCKED** (stdin에서 사용자 입력 대기)
--- 5. 연결 종료 단계 (클라이언트가 Ctrl+D 입력) ---
[클라이언트 프로세스]
- 사용자가 Ctrl+D 입력 (EOF)
- Fgets() 함수 NULL 반환
- 상태: **Running**
- while 루프 종료
- CALLS: Close(clientfd)
|
|--> [커널]
| - 클라이언트 측 소켓 닫음
| - TCP FIN 패킷을 루프백 통해 서버 측 connfd로 전송
| - 서버 프로세스 깨우기 (connfd에 EOF 이벤트)
- CALLS: printf("Connection closed.")
- CALLS: exit(0) -> 프로세스 종료
[서버 프로세스 (echo 함수 내부)]
- 상태: **WAKE UP** (Ready 상태) -> Running 상태
- Rio_readlineb() 함수 반환 (0, EOF 감지)
- while 루프 종료
- echo() 함수 종료 및 반환
[서버 프로세스 (main 함수)]
- echo() 함수로부터 복귀
- CALLS: Close(connfd) -> 해당 클라이언트 연결 소켓 닫음
- CALLS: printf("Closed connection...")
- while(1) 루프의 처음으로 돌아감
- CALLS: Accept(listenfd, ...) -> 다음 연결 기다림
- 상태: **BLOCKED** (listenfd에서 클라이언트 연결 요청 대기)

그림으로 그리면 이렇다.
소켓 프로그래밍은 네트워크 통신의 기반 위에서 동작합니다. 따라서 기본적인 TCP/IP 프로토콜 스택에 대한 이해는 필수입니다. 이 글에서는 IP, TCP, UDP 프로토콜의 특징과 TCP/IP 4계층 모델에 대해 알아보겠습니다.
네트워크 통신 과정을 역할별로 나누어 설명하는 모델입니다. OSI 7계층이 더 이론적이고 상세하며, TCP/IP 4계층(혹은 5계층) 모델이 실제 인터넷에서 주로 사용되는 모델입니다.
ping).IP 주소: 인터넷 상에서 컴퓨터(네트워크)의 논리적인 위치 (e.g., 서울시 중랑구 봉화산로 130 - 건물 주소).MAC 주소: 네트워크 카드(하드웨어)에 부여된 고유한 물리 주소 (e.g., 1203호 - 특정 세대 호수).www.naver.com 입력.www.naver.com에 해당하는 IP 주소를 찾습니다.Encapsulation, Decapsulation 과정 헷갈려서 잘못 설명함...